.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 ...
随机推荐
- chromium浏览器开发系列第五篇:Debugging with WinDBG
Windbg 相信windows开发的人都知道,有些人用的溜儿溜儿的,有个crash,直接拿这个工具一分析,就定位出来了.非常好用.以前有个同事,做sdk开发 的,会各种命令.来北京后,还去过微软面试 ...
- Struts2返回JSON数据的具体应用范…
Struts2返回JSON数据的具体应用范例 博客分类: Struts2 Struts2JSON 早在我刚学Struts2之初的时候,就想写一篇文章来阐述Struts2如何返回JSON数据的原理和具 ...
- xgene:之ROC曲线、ctDNA、small-RNA seq、甲基化seq、单细胞DNA, mRNA
灵敏度高 == 假阴性率低,即漏检率低,即有病人却没有发现出来的概率低. 用于判断:有一部分人患有一种疾病,某种检验方法可以在人群中检出多少个病人来. 特异性高 == 假阳性率低,即错把健康判定为病人 ...
- MySQL之创、增、删、改、查
MySQL Select version(); 当前服务器版本 Select database(); 查看当前工作数据库 Show databases; 显示所有数据库 Select user ...
- hduoj题目分类
基础题:1000.1001.1004.1005.1008.1012.1013.1014.1017.1019.1021.1028.1029.1032.1037.1040.1048.1056.1058.1 ...
- 常用的Elasticseaerch检索技巧汇总
本篇博客是对前期工作中遇到ES坑的一些小结,顺手记录下,方便日后查阅. 0.前言 为了讲解不同类型ES检索,我们将要对包含以下类型的文档集合进行检索: . title 标题: . authors 作者 ...
- java发送udp广播包
2013-06-07 22:44 1272人阅读 评论(2) 收藏 举报 import java.io.IOException; import java.net.DatagramPacket; imp ...
- Ext.net Calendar 控件在有模板页的时候,模板页定义了TD的样式造成日历控件的样式丢掉
Ext.net Calendar 控件在有模板页的时候,模板页定义了TD的样式造成日历控件的样式丢掉 解决方案 在本页面添加下面的样式 <style type="text/css&qu ...
- Kubernetes 集群日志管理
Kubernetes 开发了一个 Elasticsearch 附加组件来实现集群的日志管理.这是一个 Elasticsearch.Fluentd 和 Kibana 的组合.Elasticsearch ...
- Go语言入门——数组、切片和映射
按照以往开一些专题的风格,第一篇一般都是“从HelloWorld开始” 但是对于Go,思来想去,感觉真的从“HelloWorld”说起,压根撑不住一篇的篇幅,因为Go的HelloWorld太简单了. ...