.NET 读取视频文件
该篇文章 复制别人的文章
在.NET中处理视频是一件痛苦的事情,.NET并没有提供视频处理的类。于是咱们只能找一些第三方的类库或者自己实现,在项目时间比较赶的情况下,自己实现是不可能的了,而且说不定会留下很多坑。所以一般情况下,咱们都是找一些靠谱的第三方类库,毕竟别人确实实现得蛮好的。
这次的项目是一个资讯发布APP,其中一个模块功能有些类似微信朋友圈,发布内容需要支持图片、音频、视频等。其他的都很好处理,但视频的处理着实让我费了一番劲儿,之前也没有接触过视频处理的项目,甚至对视频处理的了解也挺少的。于是我Google了大半天(国内搜索引擎很少相关资料,此处建议使用Google Code),找到了一些解决方案,我选取了其中的2个。
1、AVBlocks
不得不说AVBlocks确实是做得挺不错的,其主要功能是处理视频、音频、图片等多媒体文件;AVBlocks官网提供了非常详细的Demo,比较可惜的是Demo的注释跟说明比较少(或者只是我没有发现),我在开始工作前把这个Demo里面38个项目通读了一遍(基本每个项目只包含一种功能,代码简洁)。
a)功能简介
主要包括视频的格式、流、比特率、颜色格式(Color Format)、宽高比、分辨率、帧率、扫描方式(Scan Type;这个参数我是真的不认识);
获取音频、图片信息我还没用到,不过据官网的介绍看起来还是挺好用的,AVBlocks支持的格式很多,值得一用。
b)使用方法
使用AVBlocks的方法很简单,直接在你的项目中引用 AVBlocks.clr4.x64.dll ,然后复制 AVBlocks64.dll 到你的项目生成目录下(如果是 WinForm,则复制到输出目录根目录;如果是 ASP.NET,则复制到输出目录 bin 目录)就可以了。
如果运行时报以下错误:
“无法加载 DLL“AVBlocks64.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。”
不用怀疑,肯定是你没有把AVBlocks64.dll复制到输出目录下。
c)上线注意事项
之所以写这部分是因为我在上线的时候就傻乎乎跳进了一个坑,Windows Server 2008/2008 R2/2012/2012 R2等服务器默认是没有安装wmvcore.dll。这需要我们手动安装Media Foundation(媒体基础)或者Desktop Experience(桌面体验)功能。我选择安装“桌面体验”功能。
大概操作是这样:服务器管理器->功能->添加,然后找到“桌面体验”,勾选、确定,安装完成后重启就可以了。
不然会一直报错“未将对象引用设置到对象的实例”。其实官网有说明,只是我一开始没留意。
下面是这部分的代码:
public class VideoInfo
{
//public StreamType Container { get; set; }
//public int Streams { get; set; }
public string FileName { get; set; }
public string CaptureFile { get; set; }
public MediaType MediaType { get; set; }
public StreamType StreamType { get; set; }
public StreamSubType StreamSubType { get; set; }
public int Id { get; set; }
public double Duration { get; set; }
public int Bitrate { get; set; }
public BitrateMode BitrateMode { get; set; }
public ColorFormat ColorFormat { get; set; }
public int DisplayRatioWidth { get; set; }
public int DisplayRatioHeight { get; set; }
public bool FrameBottomUp { get; set; }
public int FrameWidth { get; set; }
public int FrameHeight { get; set; }
public double FrameRate { get; set; }
public ScanType ScanType { get; set; }
}
public static VideoInfo GetVideoInfo(string inputFile)
{
VideoInfo videoInfo = new VideoInfo();
using (MediaInfo info = new MediaInfo())
{
info.Inputs[0].File = inputFile;
if (!info.Open())
{
return null;
}
videoInfo = GetStreams(info)[0];
}
// videoInfo.CaptureFile = CatchImg(inputFile, videoInfo.FrameWidth, videoInfo.FrameHeight);
return videoInfo;
}
private static List<VideoInfo> GetStreams(MediaInfo mediaInfo)
{
List<VideoInfo> videoInfos = new List<VideoInfo>();
foreach (var socket in mediaInfo.Outputs)
{
VideoInfo videoInfo = new VideoInfo();
for (int streamIndex = 0; streamIndex < socket.Pins.Count; streamIndex++)
{
StreamInfo si = socket.Pins[streamIndex].StreamInfo;
videoInfo.MediaType = si.MediaType;
videoInfo.StreamType = si.StreamType;
videoInfo.StreamSubType = si.StreamSubType;
videoInfo.Id = si.ID;
videoInfo.Duration = si.Duration;
if (MediaType.Video == si.MediaType)
{
VideoStreamInfo vsi = si as VideoStreamInfo;
videoInfo.Bitrate = vsi.Bitrate;
videoInfo.BitrateMode = vsi.BitrateMode;
videoInfo.ColorFormat = vsi.ColorFormat;
videoInfo.DisplayRatioWidth = vsi.DisplayRatioWidth;
videoInfo.DisplayRatioHeight = vsi.DisplayRatioHeight;
videoInfo.FrameBottomUp = vsi.FrameBottomUp;
videoInfo.FrameWidth = vsi.FrameWidth;
videoInfo.FrameHeight = vsi.FrameHeight;
videoInfo.FrameRate = vsi.FrameRate;
videoInfo.ScanType = vsi.ScanType;
}
videoInfos.Add(videoInfo);
}
}
return videoInfos;
}
2、FFMpeg
在项目中,我需要随机截取视频中其中一帧的图片作为视频封面,所以我找到了FFMpeg只是简单的做个截图功能。
其实FFMpeg功能很强大,想转换视频格式什么的,推荐大家有兴趣读一下这篇文章:
A Simple c# Wrapper for ffMpeg
使用也很简单,就只是调用ffMpeg.exe传入参数即可,具体参数说明可参考官方说明。
要是找不到FFMpeg.exe的下载的话,看这里:http://download.csdn.net/download/u012843100/9930545
我简单介绍下我项目中的使用:
a)复制ffMpeg.exe到系统目录下,目录随意,在第二步进行配置;
b)需在Web.config的appSettings节点中配置ffmpeg.exe的路径,<add key="ffmpeg" value="plugins\ffmpeg.exe" />;
c)上代码;
/// <summary>
/// 使用ffMpeg.exe截取视频图片(第一帧)
/// *需在Web.config的appSettings节点中配置ffmpeg.exe的路径*
/// *<add key="ffmpeg" value="plugins\ffmpeg.exe" />*
/// </summary>
/// <param name="vedioPath">视频路径</param>
/// <param name="saveImgWidth">保存的图片宽度</param>
/// <param name="saveImgHeight">保存的图片高度</param>
/// <returns>保存后的图片路径(去除基路径)</returns>
public static string CatchImg(string vedioPath, int saveImgWidth, int saveImgHeight)
{
string ffmpeg = AppDomain.CurrentDomain.BaseDirectory + "\\" + System.Configuration.ConfigurationSettings.AppSettings["ffmpeg"];
if ((!System.IO.File.Exists(ffmpeg)) || (!System.IO.File.Exists(vedioPath)))
{
return "";
}
string saveImgPath = System.IO.Path.ChangeExtension(vedioPath, ".jpg");
string saveImgSize = string.Format("{0}x{1}", saveImgWidth, saveImgHeight);
ProcessStartInfo startInfo = new ProcessStartInfo(ffmpeg);
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.Arguments = string.Format(" -i \"{0}\" -y -f image2 -t 0.001 -s \"{1}\" \"{2}\"", vedioPath, saveImgSize, saveImgPath);
System.Diagnostics.Process.Start(startInfo);
return saveImgPath.Replace(AppDomain.CurrentDomain.BaseDirectory, "");
}
以上就是这次我关于.NET视频处理的一些经验。
最后附上这个类的完整代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using PrimoSoftware.AVBlocks;
namespace JHD.Utils
{
public class AvInfoUtil
{
public class VideoInfo
{
//public StreamType Container { get; set; }
//public int Streams { get; set; }
public string FileName { get; set; }
public string CaptureFile { get; set; }
public MediaType MediaType { get; set; }
public StreamType StreamType { get; set; }
public StreamSubType StreamSubType { get; set; }
public int Id { get; set; }
public double Duration { get; set; }
public int Bitrate { get; set; }
public BitrateMode BitrateMode { get; set; }
public ColorFormat ColorFormat { get; set; }
public int DisplayRatioWidth { get; set; }
public int DisplayRatioHeight { get; set; }
public bool FrameBottomUp { get; set; }
public int FrameWidth { get; set; }
public int FrameHeight { get; set; }
public double FrameRate { get; set; }
public ScanType ScanType { get; set; }
}
public static VideoInfo GetVideoInfo(string inputFile)
{
VideoInfo videoInfo = new VideoInfo();
using (MediaInfo info = new MediaInfo())
{
info.Inputs[0].File = inputFile;
if (!info.Open())
{
return null;
}
videoInfo = GetStreams(info)[0];
}
videoInfo.CaptureFile = CatchImg(inputFile, videoInfo.FrameWidth, videoInfo.FrameHeight);
return videoInfo;
}
private static List<VideoInfo> GetStreams(MediaInfo mediaInfo)
{
List<VideoInfo> videoInfos = new List<VideoInfo>();
foreach (var socket in mediaInfo.Outputs)
{
VideoInfo videoInfo = new VideoInfo();
for (int streamIndex = 0; streamIndex < socket.Pins.Count; streamIndex++)
{
StreamInfo si = socket.Pins[streamIndex].StreamInfo;
videoInfo.MediaType = si.MediaType;
videoInfo.StreamType = si.StreamType;
videoInfo.StreamSubType = si.StreamSubType;
videoInfo.Id = si.ID;
videoInfo.Duration = si.Duration;
if (MediaType.Video == si.MediaType)
{
VideoStreamInfo vsi = si as VideoStreamInfo;
videoInfo.Bitrate = vsi.Bitrate;
videoInfo.BitrateMode = vsi.BitrateMode;
videoInfo.ColorFormat = vsi.ColorFormat;
videoInfo.DisplayRatioWidth = vsi.DisplayRatioWidth;
videoInfo.DisplayRatioHeight = vsi.DisplayRatioHeight;
videoInfo.FrameBottomUp = vsi.FrameBottomUp;
videoInfo.FrameWidth = vsi.FrameWidth;
videoInfo.FrameHeight = vsi.FrameHeight;
videoInfo.FrameRate = vsi.FrameRate;
videoInfo.ScanType = vsi.ScanType;
}
videoInfos.Add(videoInfo);
}
}
return videoInfos;
}
/// <summary>
/// 使用ffMpeg.exe截取视频图片(第一帧)
/// *需在Web.config的appSettings节点中配置ffmpeg.exe的路径*
/// *<add key="ffmpeg" value="plugins\ffmpeg.exe" />*
/// </summary>
/// <param name="vedioPath">视频路径</param>
/// <param name="saveImgWidth">保存的图片宽度</param>
/// <param name="saveImgHeight">保存的图片高度</param>
/// <returns>保存后的图片路径(去除基路径)</returns>
public static string CatchImg(string vedioPath, int saveImgWidth, int saveImgHeight)
{
string ffmpeg = AppDomain.CurrentDomain.BaseDirectory + "\\" + System.Configuration.ConfigurationSettings.AppSettings["ffmpeg"];
if ((!System.IO.File.Exists(ffmpeg)) || (!System.IO.File.Exists(vedioPath)))
{
return "";
}
string saveImgPath = System.IO.Path.ChangeExtension(vedioPath, ".jpg");
string saveImgSize = string.Format("{0}x{1}", saveImgWidth, saveImgHeight);
ProcessStartInfo startInfo = new ProcessStartInfo(ffmpeg);
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.Arguments = string.Format(" -i \"{0}\" -y -f image2 -t 0.001 -s \"{1}\" \"{2}\"", vedioPath, saveImgSize, saveImgPath);
System.Diagnostics.Process.Start(startInfo);
return saveImgPath.Replace(AppDomain.CurrentDomain.BaseDirectory, "");
}
}
}
.NET 读取视频文件的更多相关文章
- java读取视频文件时长
1.下载jar包:http://www.sauronsoftware.it/projects/jave/index.php 2.上代码 @RequestMapping(value = "am ...
- 使用ffmpeg -re循环推流(循环读取视频文件)推送EasyDSS RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器的方法
需求分析 众所周知,EasyDSS与EasyNVR最大的区别是,EasyDSS被动接受前端设备的推流,将推送过来的直播流进行直播转码.智能处理.视频分发,在通过CDN分发节点分发到终端播放SDK.而E ...
- filestream 读取视频文件
class Program { static void Main(string[] args) { string source = @"F:\361\android studio\4.0\亲 ...
- C++ 调用 opencv 读取视频文件列表并处理
//g++ trans_video.cpp -o trans_video `pkg-config opencv --libs --cflags` -L/usr/lib/x86_64-linux-gnu ...
- OpenCV3读取视频或摄像头
我们可以利用OpenCV读取视频文件或者摄像头的数据,将其保存为图像,以用于后期处理.下面的实例代码展示了简单的读取和显示操作: // This is a demo introduces you to ...
- python_Opencv_读取视频
目标 • 学会读取视频文件,显示视频,保存视频文件 • 学会从摄像头获取并显示视频 • 你将会学习到这些函数:cv2.VideoCapture(),cv2.VideoWrite()用摄像头捕获视频 使 ...
- [SimplePlayer] 1. 从视频文件中提取图像
在开始之前,我们需要了解视频文件的格式.视频文件的格式众多,无法三言两语就能详细分析其结构,尽管如此,ffmpeg却很好地提取了各类视频文件的共同特性,并对其进行了抽象描述. 视频文件格式,统称为co ...
- python opencv3 视频文件的读写
git: https://github.com/linyi0604/Computer-Vision # coding:utf8 import cv2 """ 读取视频文件 ...
- 【计算机视觉】OpenCV读取视频获取时间戳等信息(PS:经测试并不是时间戳,与FFMPEG时间戳不一样)
OpenCV中通过VideoCaptrue类对视频进行读取操作以及调用摄像头,下面是该类的API. 1.VideoCapture类的构造函数: C++: VideoCapture::VideoCapt ...
随机推荐
- JDK5特性
静态导入(了解) JDK 1.5 增加的静态导入语法用于导入类的某个静态属性或方法.使用静态导入可以简化程序对类静态属性和方法的调用. 语法: import static 包名.类名.静态属性|静态方 ...
- day6 面向对象(3)
继承 1.1 类和类之间的常见关系. 1:既然继承是描述类和类之间的关系,就需要先来了解类和类之间的常见关系 1.1.1 现实生活的整体与部分 举例说明 1:现实生活 1:学生 是人 2: ...
- linux 下消息队列发送后没有信息
在使用消息队列时,调用 #include <stdio.h> #include <stdlib.h> #include <string.h> #include &l ...
- 21.运行Consent Page
服务端把这个地方修改为true,需要设置 运行测试.服务端和客户端都运行起来 我们使用的用户是在这里配置的 服务端修改ConsentController 再次运行,但是页面都是乱码 openId和pr ...
- jquery、javascript实现(get、post两种方式)跨域解决方法
一.实现get方式跨域请求数据 浏览器端 <script> $(document).ready(function(){ $.ajax({ url: "http://www.xxx ...
- 【转】 mybatis如何在控制台打印执行的sql语句
<strong>######################################################################### #Root Logger ...
- 利用memoize缓存到Redis出现多个参数同一个结果
在为后端输出加入Redis缓存的过程中出现的问题. 在我利用Flask-restful架构的后端中,理所当然的利用装饰器marshal_with对我的返回数据进行格式化输出. 举个最简单的例子: fr ...
- Js获取当前的日期和时间以及时间戳转化为时间
/** *获取当前时间 *format=1精确到天 *format=2精确到分 */ function getCurrentDate(format) { var now = new Date(); v ...
- 集成Python Shell
每次启动shell会话都要导入Python相关对象(数据库实例和模型),这是件十分枯燥的工作.为了避免一直重复导入,我们可以做些配置,让flask-script的shell命令自动导入特定的对象. F ...
- thinkphp5部署到LAMP服务器显示Access denied.
问题:thinkphp5部署到LAMP服务器,首页正常访问,其余页面访问显示Access denied 解决:1.先把文件夹权限改为777 2. 进入服务器,改文件.将php.ini的值改成1