C# Get video file duration from metadata

2020-02-19 08:13发布

问题:

I am trying to read metadata from a file. I only need the Video -> Length property, however I am unable to find a simple way of reading this information.

I figured this would be fairly easy since it is visible by default in Explorer, however this looks to be way more complicated than I anticipated. The closest I came was using:

Microsoft.DirectX.AudioVideoPlayback.Video video = new Microsoft.DirectX.AudioVideoPlayback.Video(str);
double duration = video.Duration;

However this throws a LoaderLock exception, and I don't know how to deal with it.

Any ideas?

回答1:

Many of these details are provided by the shell, so you can do this by adding a reference to the COM Library "Microsoft Shell Controls and Automation" (Shell32), and then using the Folder.GetDetailsOf method to query the extended details.

I was recently looking for this and came across this very question on the MSDN C# General forums. I wound up writing this as an extension method to FileInfo:

    public static Dictionary<string, string> GetDetails(this FileInfo fi)
    {
        Dictionary<string, string> ret = new Dictionary<string, string>();
        Shell shl = new ShellClass();
        Folder folder = shl.NameSpace(fi.DirectoryName);
        FolderItem item = folder.ParseName(fi.Name);

        for (int i = 0; i < 150; i++)
        {
            string dtlDesc = folder.GetDetailsOf(null, i);
            string dtlVal = folder.GetDetailsOf(item, i);

            if (dtlVal == null || dtlVal == "")
                continue;

            ret.Add(dtlDesc, dtlVal);
        }
        return ret;
    }

If you're looking for specific entries, you can do something similar, though it will be far faster to find out what index those entries are at (Length is index 27 I believe) and just query those. Note, I didn't do much research into whether or not the index can change (I doubt it), which is why I took the dictionary approach.



回答2:

Take a look at this SO question - Solid FFmpeg wrapper for C#/.NET which links to several ffmpeg .Net implementations. ffmpeg works with most video formats/codecs. That way you don't need to worry about the codec being installed on the machine.

Or look at https://mediaarea.net/en/MediaInfo.



回答3:

I would have just commented on Mikael's post, but I don't quite have enough rep to do it yet. I agree with him on using ffmpeg so that you don't have to require that codecs be installed. You could just parse the output of "ffmpeg -i your_filename" which will just dump some info about the video including the duration.

I don't know what codecs you're working with, but some containers do not actually store the duration in the metadata (this is common of streaming containers since duration is unknown). I don't know how ffmpeg handles this, but it seems to find it somehow (maybe by parsing the whole file for timecodes).



回答4:

You can use our wrapper for ffprobe Alturos.VideoInfo. You can use it simply by installing the nuget package. Also the ffprobe binary is required.

PM> install-package Alturos.VideoInfo

Example

var videoFilePath = "myVideo.mp4";

var videoAnalyer = new VideoAnalyzer("ffprobe.exe");
var analyzeResult = videoAnalyer.GetVideoInfo(videoFilePath);

//Video length
var duration = analyzeResult.VideoInfo.Format.Duration;


回答5:

I recommend to use MediaToolkit nuget package. It does not require COM interop on your code.

using MediaToolkit;

// a method to get Width, Height, and Duration in Ticks for video.
public static Tuple<int, int, long> GetVideoInfo(string fileName)
{
    var inputFile = new MediaToolkit.Model.MediaFile { Filename = fileName };
    using (var engine = new Engine())
    {
        engine.GetMetadata(inputFile);
    }

    // FrameSize is returned as '1280x768' string.
    var size = inputFile.Metadata.VideoData.FrameSize.Split(new[] { 'x' }).Select(o => int.Parse(o)).ToArray();

    return new Tuple<int, int, long>(size[0], size[1], inputFile.Metadata.Duration.Ticks);
}


回答6:

using DirectShowLib (http://directshownet.sourceforge.net/)

   /// <summary>
    /// Gets the length of the video.
    /// </summary>
    /// <param name="fileName">Name of the file.</param>
    /// <param name="length">The length.</param>
    /// <returns></returns>
    static public bool GetVideoLength(string fileName, out double length)
    {
        DirectShowLib.FilterGraph graphFilter = new DirectShowLib.FilterGraph();
        DirectShowLib.IGraphBuilder graphBuilder;
        DirectShowLib.IMediaPosition mediaPos;
        length = 0.0;

        try
        {
            graphBuilder = (DirectShowLib.IGraphBuilder)graphFilter;
            graphBuilder.RenderFile(fileName, null);
            mediaPos = (DirectShowLib.IMediaPosition)graphBuilder;
            mediaPos.get_Duration(out length);
            return true;
        }
        catch
        {
            return false;
        }
        finally
        {
            mediaPos = null;
            graphBuilder = null;
            graphFilter = null;
        }
    }


回答7:

Getting duration of video file in Win Rt App or Metro C#:

StorageFile videoFile;
videoFile = await StorageFile.GetFileFromPathAsync(VIDEO_PATH_HERE);
Windows.Storage.FileProperties.VideoProperties x = await videoFile.Properties.GetVideoPropertiesAsync();
var videoDuration = x.Duration;


回答8:

MediaInfo is a great open source library for that purpose (the DLL is licensed LGPL). The download package contains sample application in C# (under Developers\Project\MSCS\Example)



回答9:

I had the same issue with a small video preview app.

The issue is Managed Debugging Assisstants. This is an issue when using The Managed DirectX 1.1 libraries in VS2005 or 2008. Microsoft has moved on to focus on MDX2 and then XNA rather than Managed DirectX 1 so don't hope too much for a patch.

The easy workaround is to disable the LoaderLock Exception handling while debugging that solution. This should have no real effect on the program anyways since this error only shows up in a debug environment.

To disable go to Debug -> Exceptions -> Managed Debugging Assistants and uncheck LoaderLock.

More info here:http://vivekthangaswamy.blogspot.com/2006/11/loaderlock-was-detected-error-when.html



回答10:

use MCI

its easy to use and works even on NT:

  using System.Runtime.InteropServices;

  [DllImport("winmm.dll")]
  public static extern int mciSendString(string lpstrCommand, StringBuilder lpstrReturnString, int uReturnLength, int hwndCallback);
  [DllImport("winmm.dll")]
  private static extern int mciGetErrorString(int l1, StringBuilder s1, int l2);

  string cmd = "open " + strFile + " alias video";
  StringBuilder mssg = new StringBuilder(255);

  int h = mciSendString(cmd, null, 0, 0); // open video at mci
  int i = mciSendString("set video time format ms", null, 0, 0); // set time format, you can see other formats at link above
  int j = mciSendString("status video length", mssg, mssg.Capacity, 0); //get video length into mssg 
  Console.WriteLine(mssg.ToString());
  int m = mciSendString("close video", null, 0, 0); //close video


回答11:

It seems that I am posting, what I have tried, so late. Hope it will help someone.

I have tried to get the video length in a bit different way by sing Windows Media Player Component.
Following code snippet may help you guys :

using WMPLib;
// ...your code here...

var player = new WindowsMediaPlayer();
var clip = player.newMedia(filePath);
Console.WriteLine(TimeSpan.FromSeconds(clip.duration));

and don't forget to add the reference of wmp.dll which will be present in System32 folder.



标签: c# metadata