Skip to content

Instantly share code, notes, and snippets.

@nrk
Created April 2, 2012 19:19
Show Gist options
  • Save nrk/2286511 to your computer and use it in GitHub Desktop.
Save nrk/2286511 to your computer and use it in GitHub Desktop.
Using ffprobe to get info from a file in a nice JSON format
ffprobe -v quiet -print_format json -show_format -show_streams "lolwut.mp4" > "lolwut.mp4.json"
{
"streams": [
{
"index": 0,
"codec_name": "h264",
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
"codec_type": "video",
"codec_time_base": "1001/48000",
"codec_tag_string": "avc1",
"codec_tag": "0x31637661",
"width": 1280,
"height": 720,
"has_b_frames": 0,
"pix_fmt": "yuv420p",
"level": 31,
"is_avc": "1",
"nal_length_size": "4",
"r_frame_rate": "35029/1461",
"avg_frame_rate": "35029/1461",
"time_base": "1/35029",
"start_time": "0.000000",
"duration": "1239.195267",
"bit_rate": "1782423",
"nb_frames": "29711",
"tags": {
"creation_time": "1970-01-01 00:00:00",
"language": "und",
"handler_name": "VideoHandler"
}
},
{
"index": 1,
"codec_name": "aac",
"codec_long_name": "Advanced Audio Coding",
"codec_type": "audio",
"codec_time_base": "1/48000",
"codec_tag_string": "mp4a",
"codec_tag": "0x6134706d",
"sample_fmt": "s16",
"sample_rate": "48000",
"channels": 2,
"bits_per_sample": 0,
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/48000",
"start_time": "0.000000",
"duration": "1239.059396",
"bit_rate": "127966",
"nb_frames": "58081",
"tags": {
"creation_time": "2012-04-01 15:42:28",
"language": "jpn",
"handler_name": "GPAC ISO Audio Handler"
}
}
],
"format": {
"filename": "lolwut.mp4",
"nb_streams": 2,
"format_name": "mov,mp4,m4a,3gp,3g2,mj2",
"format_long_name": "QuickTime/MPEG-4/Motion JPEG 2000 format",
"start_time": "0.000000",
"duration": "1239.195000",
"size": "296323860",
"bit_rate": "1913008",
"tags": {
"major_brand": "isom",
"minor_version": "1",
"compatible_brands": "isom",
"creation_time": "2012-04-01 15:42:24"
}
}
}
@daiplusplus
Copy link

daiplusplus commented Mar 24, 2022

If anyone wants it, here's my quick-and-dirty Newtonsoft.Json-compatible C# class for ffprobe's -print_format json -show_format -show_streams output:

Usage: If you've got ffprobe's output in a String ffprobeJsonOutput then just do FFProbeJsonOutput? parsedOutput = JsonConvert.DeserializeObject<FFProbeJsonOutput>( ffprobeJsonOutput );.

Almost every member is marked nullable because I wasn't sure which JSON properties FFprobe will always return for all formats/codecs.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;

using Newtonsoft.Json;

namespace MyProject
{
	public class FFProbeJsonOutput
	{
		/// <summary>Information about the streams within the container.</summary>
		[JsonProperty("streams")]
		[SuppressMessage( "Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly" )]
		public List<FFProbeStream>? Streams { get; set; }

		/// <summary>Information about the container.</summary>
		[JsonProperty("format")]
		public FFProbeFormat? Format { get; set; }
	}

	public class FFProbeStream
	{
		[JsonProperty("index")]
		public Int32 Index { get; set; }

		[JsonProperty("codec_name")]
		public String? CodecName { get; set; }

		/// <summary>Values like &quot;H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10&quot;.</summary>
		[JsonProperty("codec_long_name")]
		public String? CodecLongName { get; set; }

		[JsonProperty("codec_type")]
		public String? CodecType { get; set; }

		/// <summary>Contains the FourCC of a video codec or the TwoCC of an audio codec - or another textual representation as FourCC/TwoCC is container-specific!</summary>
		[JsonProperty("codec_tag_string")]
		public String? CodecTag { get; set; }

		/// <summary>Codec/format-specific profile information, e.g. for AVC (H.264) this may be &quot;High&quot; but for AAC this may be &quot;LC&quot;.</summary>
		[JsonProperty("profile")]
		public String? Profile { get; set; }

		[JsonProperty("level")]
		public Int32? Level { get; set; }

		/// <summary>Only specified for Video streams.</summary>
		[JsonProperty("width")]
		public Int32? Width { get; set; }

		/// <summary>Only specified for Video streams.</summary>
		[JsonProperty("height")]
		public Int32? Height { get; set; }

		// Don't worry about `coded_width`/`coded_height`, that's for when a video codec requires the encoded video's dimensions to be a multiple of a block-size, but the video is still cropped to an arbitrary size (the `width`/`height`) when rendered.

		[JsonProperty("duration")]
		public Double? Duration { get; set; }

		/// <summary>Duration expressed in integer time-base units (https://video.stackexchange.com/questions/27546/difference-between-duration-ts-and-duration-in-ffprobe-output</summary>
		[JsonProperty("duration_ts")]
		public Int64? DurationTS { get; set; }

		/// <summary>Values like &quot;1/600&quot;. See https://stackoverflow.com/questions/43333542/what-is-video-timescale-timebase-or-timestamp-in-ffmpeg </summary>
		[JsonProperty("time_base")]
		public String? TimeBase { get; set; }

		/// <summary>Stream-specific tags/metadata. See <see cref="KnownFFProbeVideoStreamTags"/>.</summary>
		[SuppressMessage( "Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly" )]
		[JsonProperty("tags")]
		public Dictionary<String,String>? Tags { get; set; }
	}

	public class FFProbeFormat
	{
		[JsonProperty("filename")]
		public String? FileName { get; set; }

		[JsonProperty("nb_streams")]
		public Int32? NBStreams { get; set; }

		[JsonProperty("nb_programs")]
		public Int32? NBPrograms { get; set; }

		[JsonProperty("format_name")]
		public String? FormatName { get; set; }

		[JsonProperty("format_long_name")]
		public String? FormatLongName { get; set; }

		/// <summary>Approximate duration in seconds (it's approximate because videos can start *after* the 00:00:00 timecode, e.g. see this SO question with a video that starts at 0.04: https://superuser.com/questions/650291/how-to-get-video-duration-in-seconds ).</summary>
		[JsonProperty("duration")]
		public Double? Duration { get; set; }

		[JsonProperty("bit_rate")]
		public Int32? BitRate { get; set; }

		[JsonProperty("probe_score")]
		public Int32? ProbeScore { get; set; }

		/// <summary>Container and format tags/metadata, not stream-specific tags. See <see cref="KnownFFProbeFormatTags"/>.</summary>
		[SuppressMessage( "Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly" )]
		[JsonProperty("tags")]
		public Dictionary<String,String>? Tags { get; set; }
	}

	/// <summary>Known tag-names for <see cref="FFProbeStream"/>'s <see cref="FFProbeStream.Tags"/>.</summary>
	public static class KnownFFProbeVideoStreamTags
	{
		/// <summary>Tag value is a decimal integer value in degrees, e.g. &quot;90&quot;.</summary>
		public const String Rotate = "rotate";

		/// <summary>Tag value is ISO 8601 e.g. &quot;2020-04-21T15:22:51.000000Z&quot;.</summary>
		public const String CreationTime = "creation_time";

		/// <summary>Values like &quot;H.264&quot;.</summary>
		public const String Encoder = "encoder";
	}

	/// <summary>Known tag-names for <see cref="FFProbeFormat"/>'s <see cref="FFProbeFormat.Tags"/>.</summary>
	public static class KnownFFProbeFormatTags
	{
		/// <summary>MPEG-4 container &quot;brand&quot; identifier.</summary>
		public const String MajorBrand = "major_brand";

		/// <summary>Tag value is ISO 8601 e.g. &quot;2020-04-21T15:22:51.000000Z&quot;.</summary>
		public const String CreationTime = "creation_time";

		/// <summary>E.g. &quot;Apple&quot;.</summary>
		public const String AppleMake     = "com.apple.quicktime.make";

		/// <summary>E.g. &quot;iPhone 8 Plus&quot;.</summary>
		public const String AppleModel    = "com.apple.quicktime.model";

		/// <summary>I think this is the iOS/iPhone OS software version if it's from an iPhone, e.g. &quot;13.4.1&quot;.</summary>
		public const String AppleSoftware = "com.apple.quicktime.software";
	}

	public static class FFProbeOutputExtensions
	{
		public static FFProbeStream? GetFirstVideoStreamOrNull( this FFProbeJsonOutput json )
		{
			if( json.Streams != null )
			{
				return json.Streams.FirstOrDefault( s => "video".Equals( s.CodecType, StringComparison.OrdinalIgnoreCase ) );
			}
			else
			{
				return null;
			}
		}

		public static FFProbeStream? GetFirstAudioStreamOrNull( this FFProbeJsonOutput json )
		{
			if( json.Streams != null )
			{
				return json.Streams.FirstOrDefault( s => "audio".Equals( s.CodecType, StringComparison.OrdinalIgnoreCase ) );
			}
			else
			{
				return null;
			}
		}

		public static Int32? GetRotation( this FFProbeStream ffProbeStream )
		{
			if( ffProbeStream.Tags != null )
			{
				if( ffProbeStream.Tags.TryGetValue( KnownFFProbeVideoStreamTags.Rotate, value: out String? rotateTagValue ) )
				{
					if( Int32.TryParse( rotateTagValue, NumberStyles.Any, CultureInfo.InvariantCulture, out Int32 rotateTagValueInt ) )
					{
						return rotateTagValueInt;
					}
				}
			}

			return null;
		}

		/// <summary>If the <see cref="FFProbeJsonOutput.Format"/> has a duration, that's returned - otherwise the first stream duration is returned. Returns null if none of the streams (nor the <see cref="FFProbeJsonOutput.Format"/>) has a duration value set.</summary>
		public static TimeSpan? GetDuration( this FFProbeJsonOutput ffProbeOutput )
		{
			if( ffProbeOutput.Format != null )
			{
				Double? d = ffProbeOutput.Format.Duration;
				if( d.HasValue )
				{
					return TimeSpan.FromSeconds( d.Value );
				}
			}

			if( ffProbeOutput.Streams != null )
			{
				foreach( FFProbeStream? stream in ffProbeOutput.Streams )
				{
					Double? d = stream?.Duration;
					if( d.HasValue )
					{
						return TimeSpan.FromSeconds( d.Value );
					}
				}
			}

			return null;
		}
	}
}

@gqtn
Copy link

gqtn commented May 6, 2022

Hello.

Great list! However, does anyone know how to find the duration of stream (HLS or MPEG-DASH) segments?

@daiplusplus
Copy link

daiplusplus commented Jun 8, 2022

@quintanaplaca I believe that information is in the .m3u8 file's #EXTINF tags, and not the segment blob (while a segment blob will have a duration, I think (though am uncertain) that clients will prefer timing data from the m3u8 file as that's more canonical.... or something. YMMV. IANAL. Etc.

To quote Apple: https://developer.apple.com/documentation/http_live_streaming/example_playlists_for_http_live_streaming/video_on_demand_playlist_construction (emphasis mine)

#EXTINF: A record marker that describes the media file identified by the URL that follows it. Each media file URL must be preceded by an EXTINF tag. This tag contains a duration attribute that's an integer or floating-point number in decimal positional notation that specifies the duration of the media segment in seconds. This value must be less than or equal to the target duration.

@gqtn
Copy link

gqtn commented Jun 10, 2022

@Jehoel, thank you for your reply. Really, you are right. I would like a way to analyze HLS and MPEG-DASH stream with FFmpeg (the segmentSize, segmentDuration) and check its integrity.

@irzhywau
Copy link

irzhywau commented Sep 7, 2023

is there a way to grab these informations using one of library provided by ffmpeg using C?

@teknoraver
Copy link

nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment