Media.Open reads a video file’s structure and gives you its duration, each track’s codec, the frame size and frame rate, and the audio sample rate, in managed code with no FFmpeg or ffprobe. It reads MP4, MOV, 3GP and fragmented MP4, and MKV and WebM. The two inputs here are the same five-second clip from MDN’s CC0 sample videos, as H.264/AAC in MP4 and VP8/Vorbis in WebM.
dotnet new console -o VideoInfo && cd VideoInfo dotnet add package RecursiveAI.OneMedia --version 0.1.0-preview.1 m=https://interactive-examples.mdn.mozilla.net/media/cc0-videos curl -L -o flower.mp4 $m/flower.mp4 curl -L -o flower.webm $m/flower.webm
Put this in Program.cs and run dotnet run:
using RecursiveAI.OneMedia; using RecursiveAI.OneMedia.Codecs; foreach (string path in new[] { "flower.mp4", "flower.webm" }) { using MediaFile media = Media.Open(path); Console.WriteLine($"{path}: {media.Format}, {media.Duration:mm\\:ss\\.fff}"); if (media.Video is { Video: { } v } video) { double fps = (double)v.FrameRateNumerator / v.FrameRateDenominator; Console.WriteLine($" video {video.Codec} {v.Width}x{v.Height} {fps:0.###} fps" + $" {CodecString(video)}"); } if (media.Audio is { Audio: { } a } audio) Console.WriteLine($" audio {audio.Codec} {a.SampleRate} Hz {a.Channels} ch" + $" {CodecString(audio)}"); } // Parses the codec configuration (avcC, esds, CodecPrivate...) for the details. static string CodecString(MediaTrack track) => CodecParameterReader.TryDescribe(track.Codec, track.Configuration, out CodecParameters? p) && p is not null ? $"[{p.Rfc6381}{(p.ProfileName is { Length: > 0 } n ? $", {n}" : "")}]" : "";
flower.mp4: isobmff, 00:05.055 video h264 960x540 29.97 fps [avc1.64001F, High] audio aac 48000 Hz 2 ch [mp4a.40.2, LC] flower.webm: matroska, 00:05.059 video vp8 960x540 29.97 fps audio vorbis 44100 Hz 2 ch [vorbis]
media.Duration is a TimeSpan?; it is null only when the file doesn’t state one. media.Video and media.Audio are the first video and audio tracks; media.Tracks lists them all (see List the tracks of a video). The frame size is the coded size; RotationDegrees on the same record says whether a player turns it (see Get video rotation).
The RFC 6381 string is what an HTML <source type="video/mp4; codecs=…"> or a DASH/HLS manifest wants. The same CodecParameters record carries the profile and level, bit depth, chroma format, color description, pixel aspect ratio and, for audio, the sample rate and channel count from the codec header itself.
Check it with ffprobe
If you have FFmpeg installed, ffprobe reports the same figures:
ffprobe -v error -show_entries format=duration:stream=codec_name,width,height,r_frame_rate,sample_rate -of compact flower.mp4stream|codec_name=h264|width=960|height=540|r_frame_rate=30000/1001 stream|codec_name=aac|sample_rate=48000|r_frame_rate=0/0 format|duration=5.055000
Limits
- No decoding. OneMedia reads what the container and codec headers state. It can’t grab a frame, make a thumbnail or measure anything that needs decoded pixels or samples.
- Formats. MP4, MOV, 3GP/3G2, M4A/M4V, fragmented MP4, MKV, MKA, MK3D and WebM only in 0.1. AVI, MPEG-TS, Ogg, FLV and the rest throw
UnsupportedMediaException. - Codec strings.
Rfc6381comes from the codec header parsers, so a track whose codec has none (VP8 here) gets no string. The parsers cover H.264, HEVC, H.266, AV1, VP8/VP9, AAC, MP3, Opus, Vorbis, FLAC, AC-3 and others: Codec headers. - Frame rate. It is the nominal rate the container states: the sample durations in MP4,
DefaultDurationin Matroska (which gives fractions such as 500000000/16683333). Both are 0 when the file doesn’t say, so check before dividing. - Fragmented MP4 duration is structural: it comes from the headers, and the fragments are not scanned. See MP4, MOV and 3GP.
For tags such as title and artist, see Read MP4 metadata.