基于AForge實(shí)現(xiàn)C#攝像頭視頻錄制功能
本文為大家分享了AForge實(shí)現(xiàn)C#攝像頭視頻錄制功能的具體方法,供大家參考,具體內(nèi)容如下
1. 概述
最近由于興趣學(xué)習(xí)了下在C#上使用AForge錄制攝像頭視頻并壓縮編碼。總體上來(lái)說(shuō)這個(gè)第三方.net視覺(jué)開(kāi)發(fā)庫(kù)還是比較穩(wěn)定的(AForge lib下載、離線幫助文檔下載)。但是由于這個(gè)第三方庫(kù)維護(hù)不怎么樣,導(dǎo)致會(huì)出現(xiàn)不兼容的問(wèn)題。這里將這些與大家分享,希望對(duì)您有幫助。
在使用AForge第三方庫(kù)錄制本地視頻所要使用到的類主要有這幾個(gè):FilterInfoCollection、VideoCaptureDevice、VideoSourcePlayer、VideoFileWriter。下面我就簡(jiǎn)單的介紹一下這幾個(gè)類涉及到的方法等。
FilterInfoCollection:
該類主要是用于攝像頭視頻輸入設(shè)備列表檢測(cè)的。是繼承自C#中的System.Collections.CollectionBase類。

這是離線幫助文檔上對(duì)這個(gè)類的調(diào)用方式:

其中構(gòu)造函數(shù)傳遞進(jìn)去的參數(shù)是需要采集的信號(hào)的類型,他還有其他的輸入類型(如聲音等):

VideoCaptureDevice:
這是該類中的一些成員函數(shù)和變量



這個(gè)類便是要選擇了視頻輸入的設(shè)備了,他的構(gòu)造函數(shù)是

在實(shí)際的使用過(guò)程中可能會(huì)存在多個(gè)設(shè)備的情況,便可以通過(guò)第二個(gè)參數(shù)進(jìn)行輸入設(shè)備的指定。初始化是這樣的

在本例子的實(shí)際使用過(guò)程中對(duì)上面該類事件NewFrame函數(shù)進(jìn)行了響應(yīng),然后提取出當(dāng)前幀。
VideoSourcePlayer:
該類是AForge.Control中的類,是控件中調(diào)用的,這里將它添加進(jìn)來(lái)是為了作為拍照功能使用的,這里就不做介紹了。
VideoFileWriter:
該類是視頻寫(xiě)操作類,主要實(shí)現(xiàn)視頻文件的壓縮和寫(xiě)入到文件中。
本例子中先使用VideoFileWriter.Open()函數(shù)設(shè)定錄制視頻的高度、寬度、幀率、編碼類型。

這是該第三方類庫(kù)支持的視頻編碼格式

然后使用下面這個(gè)函數(shù)就可以將當(dāng)前幀寫(xiě)入到視頻文件中了。

2. 實(shí)現(xiàn)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
//using AForge
using AForge;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;
using AForge.Controls;
namespace video_record
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//關(guān)閉窗口響應(yīng)函數(shù)
private void button2_Click(object sender, EventArgs e)
{
if (this.writer.IsOpen)
{
MessageBox.Show("視頻流還沒(méi)有寫(xiě)完,請(qǐng)點(diǎn)擊結(jié)束錄制。", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
this.videoSource.SignalToStop();
this.videoSource.WaitForStop();
this.videoSourcePlayer.SignalToStop();
this.videoSourcePlayer.WaitForStop();
this.Hide();
this.Close();
this.Dispose();
}
private FilterInfoCollection videoDevices; //攝像頭設(shè)備
private VideoCaptureDevice videoSource; //視頻的來(lái)源選擇
private VideoSourcePlayer videoSourcePlayer; //AForge控制控件
private VideoFileWriter writer; //寫(xiě)入到視頻
private bool is_record_video = false; //是否開(kāi)始錄像
System.Timers.Timer timer_count;
int tick_num = 0;
//窗體初始化函數(shù)
private void Form1_Load(object sender, EventArgs e)
{
this.label5.Visible = false;
this.videoSourcePlayer = new AForge.Controls.VideoSourcePlayer();
this.videoSource = new VideoCaptureDevice();
this.writer = new VideoFileWriter();
//設(shè)置視頻編碼格式
this.comboBox_videoecode.Items.Add("Raw");
this.comboBox_videoecode.Items.Add("MPEG2");
this.comboBox_videoecode.Items.Add("FLV1");
this.comboBox_videoecode.Items.Add("H263p");
this.comboBox_videoecode.Items.Add("MSMPEG4v3");
this.comboBox_videoecode.Items.Add("MSMPEG4v2");
this.comboBox_videoecode.Items.Add("WMV2");
this.comboBox_videoecode.Items.Add("WMV1");
this.comboBox_videoecode.Items.Add("MPEG4");
this.comboBox_videoecode.SelectedIndex = 1;
//設(shè)置視頻來(lái)源
try
{
// 枚舉所有視頻輸入設(shè)備
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (videoDevices.Count == 0)
throw new ApplicationException(); //沒(méi)有找到攝像頭設(shè)備
foreach (FilterInfo device in videoDevices)
{
this.comboBox_camera.Items.Add(device.Name);
}
//this.comboBox_camera.SelectedIndex = 0; //注釋掉,選擇攝像頭來(lái)源的時(shí)候才會(huì)才會(huì)觸發(fā)顯示攝像頭信息
}
catch (ApplicationException)
{
videoDevices = null;
MessageBox.Show("沒(méi)有找到攝像頭設(shè)備", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//秒表
this.timer_count = new System.Timers.Timer(); //實(shí)例化Timer類,設(shè)置間隔時(shí)間為10000毫秒;
this.timer_count.Elapsed += new System.Timers.ElapsedEventHandler(tick_count); //到達(dá)時(shí)間的時(shí)候執(zhí)行事件;
this.timer_count.AutoReset = true; //設(shè)置是執(zhí)行一次(false)還是一直執(zhí)行(true);
this.timer_count.Interval = 1000;
}
//視頻源選擇下拉框選擇之后的響應(yīng)函數(shù)
private void comboBox_camera_SelectedIndexChanged(object sender, EventArgs e)
{
int selected_index = this.comboBox_camera.SelectedIndex;
this.videoSource = new VideoCaptureDevice(videoDevices[selected_index].MonikerString);
// set NewFrame event handler
videoSource.NewFrame += new NewFrameEventHandler(show_video);
videoSource.Start();
videoSourcePlayer.VideoSource = videoSource;
videoSourcePlayer.Start();
this.label5.Text = "連接中...";
this.label5.Visible = true;
isshowed = true;
}
bool isshowed = true;
//新幀的觸發(fā)函數(shù)
private void show_video(object sender, NewFrameEventArgs eventArgs)
{
if (isshowed)
{
this.label5.Visible = false;
isshowed = false;
}
Bitmap bitmap = eventArgs.Frame; //獲取到一幀圖像
pictureBox1.Image = Image.FromHbitmap(bitmap.GetHbitmap());
if (is_record_video)
{
writer.WriteVideoFrame(bitmap);
}
}
//拍攝圖像按鈕響應(yīng)函數(shù)
private void button1_Click(object sender, EventArgs e)
{
if (this.videoSource.IsRunning && this.videoSourcePlayer.IsRunning)
{
Bitmap bitmap = this.videoSourcePlayer.GetCurrentVideoFrame();
bitmap.Save("img.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
else
MessageBox.Show("攝像頭沒(méi)有運(yùn)行", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
//開(kāi)始錄像按鈕響應(yīng)函數(shù)
private void button_start_Click(object sender, EventArgs e)
{
int width = 640; //錄制視頻的寬度
int height = 480; //錄制視頻的高度
int fps = 9;
//創(chuàng)建一個(gè)視頻文件
String video_format = this.comboBox_videoecode.Text.Trim(); //獲取選中的視頻編碼
if (this.videoSource.IsRunning && this.videoSourcePlayer.IsRunning)
{
if (-1 != video_format.IndexOf("MPEG"))
{
writer.Open("test.avi", width, height, fps, VideoCodec.MPEG4);
}
else if (-1 != video_format.IndexOf("WMV"))
{
writer.Open("test.wmv", width, height, fps, VideoCodec.WMV1);
}
else
{
writer.Open("test.mkv", width, height, fps, VideoCodec.Default);
}
}
else
MessageBox.Show("沒(méi)有視頻源輸入,無(wú)法錄制視頻。", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
timer_count.Enabled = true;//是否執(zhí)行System.Timers.Timer.Elapsed事件;
this.label5.Visible = true;
this.label5.Text = "REC";
this.is_record_video = true;
}
//停止錄制視頻響應(yīng)函數(shù)
private void button_stop_Click(object sender, EventArgs e)
{
this.label5.Visible = false;
this.is_record_video = false;
this.writer.Close();
this.timer_count.Enabled = false;
tick_num = 0;
}
//暫停按鈕響應(yīng)函數(shù)
private void button3_Click(object sender, EventArgs e)
{
if (this.button3.Text.Trim() == "暫停錄像")
{
this.is_record_video = false;
this.label5.Visible = false;
this.button3.Text = "恢復(fù)錄像";
timer_count.Enabled = false; //暫停計(jì)時(shí)
return;
}
if (this.button3.Text.Trim() == "恢復(fù)錄像")
{
this.is_record_video = true;
timer_count.Enabled = true; //恢復(fù)計(jì)時(shí)
this.label5.Visible = true;
this.button3.Text = "暫停錄像";
}
}
//計(jì)時(shí)器響應(yīng)函數(shù)
public void tick_count(object source, System.Timers.ElapsedEventArgs e)
{
tick_num++;
int temp = tick_num;
int sec = temp % 60;
int min = temp / 60;
if (60 == min)
{
min = 0;
min++;
}
int hour = min / 60;
String tick = hour.ToString() + ":" + min.ToString() + ":" + sec.ToString();
this.label4.Text = tick;
}
}
}
3. 結(jié)果

4. 錯(cuò)誤和注意事項(xiàng)
1. 在使用AForge這個(gè)軟件過(guò)程中需要的不僅僅是將Release文件夾下對(duì)應(yīng)的lib添加到項(xiàng)目的引用中,在進(jìn)行視頻壓縮編碼的時(shí)候需要將External文件夾下的相關(guān)lib添加到程序運(yùn)行的Debug目錄下

2. 在使用的時(shí)候會(huì)遇到這個(gè)錯(cuò)誤“混合模式程序集是針對(duì)“v2.0.50727”版的運(yùn)行時(shí)生成的,在沒(méi)有配置其他信息的情況”的錯(cuò)誤。這是因?yàn)?net框架不兼容的問(wèn)題,AForge使用的比較老好像是2.0的。。。-_-||。所以需要在App.config對(duì)其進(jìn)行配置,使其對(duì)前版本的兼容,配置如下(這是我添加的配置):
<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> <supportedRuntime version="v2.0.50727"/> </startup>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#使用ffmpeg實(shí)現(xiàn)將圖片保存為mp4視頻
FFmpeg是一個(gè)開(kāi)源的跨平臺(tái)多媒體處理工具,它提供了強(qiáng)大的功能,包括頻和視頻編碼、解碼、轉(zhuǎn)碼等,本文我們將使用FFmpeg實(shí)現(xiàn)將圖片保存為mp4視頻,感興趣的可以了解下2024-11-11
C# 中使用Stopwatch計(jì)時(shí)器實(shí)現(xiàn)暫停計(jì)時(shí)繼續(xù)計(jì)時(shí)功能
這篇文章主要介紹了C# 中使用Stopwatch計(jì)時(shí)器可暫停計(jì)時(shí)繼續(xù)計(jì)時(shí),主要介紹stopwatch的實(shí)例代碼詳解,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
C#實(shí)現(xiàn)循環(huán)發(fā)送電腦屏幕截圖
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)循環(huán)發(fā)送電腦屏幕截圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
C#中Timer實(shí)現(xiàn)Tick使用精度的問(wèn)題
這篇文章主要介紹了C#中Timer實(shí)現(xiàn)Tick使用精度的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
C#實(shí)現(xiàn)簡(jiǎn)單的Login窗口實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)簡(jiǎn)單的Login窗口,實(shí)例分析了C#顯示及關(guān)閉登陸Login窗口的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-08-08
C# 數(shù)獨(dú)求解算法的實(shí)現(xiàn)
這篇文章主要介紹了C# 數(shù)獨(dú)求解算法的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
C#中圖片旋轉(zhuǎn)和翻轉(zhuǎn)(RotateFlipType)用法分析
這篇文章主要介紹了C#中圖片旋轉(zhuǎn)和翻轉(zhuǎn)(RotateFlipType)用法,實(shí)例分析了C#圖片旋轉(zhuǎn)及翻轉(zhuǎn)Image.RotateFlip方法屬性的常用設(shè)置技巧,需要的朋友可以參考下2015-06-06

