zoukankan      html  css  js  c++  java
  • .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(桌面体验)功能。我选择安装“桌面体验”功能。
    大概操作是这样:服务器管理器->功能->添加,然后找到“桌面体验”,勾选、确定,安装完成后重启就可以了。

    不然会一直报错“未将对象引用设置到对象的实例”。其实官网有说明,只是我一开始没留意。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20


    下面是这部分的代码:


    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;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    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="pluginsffmpeg.exe" />;
    c)上代码;
    1
    2
    3


    /// <summary>
    /// 使用ffMpeg.exe截取视频图片(第一帧)
    /// *需在Web.config的appSettings节点中配置ffmpeg.exe的路径*
    /// *<add key="ffmpeg" value="pluginsffmpeg.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, "");
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    以上就是这次我关于.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="pluginsffmpeg.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, "");
    }
    }
    }
    ---------------------
    作者:lyzcren
    来源:CSDN
    原文:https://blog.csdn.net/u012843100/article/details/77113385
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    用Django开发简单的POST/GET接口
    搭建Django环境
    用Django创建一个项目
    NodeJS服务器退出:完成任务,优雅退出
    linux 常用bash
    泛型笔记
    finderweb日志查看系统配置使用
    finderweb日志查看系统部署
    jenkins+gitlab自动部署代码
    jenkins 配置 git拉取代码
  • 原文地址:https://www.cnblogs.com/zxtceq/p/10121404.html
Copyright © 2011-2022 走看看