How to get native frame rate of vide with FFmpex?

Viewed 63

Background

I have an .mp4 video and I need to get the video's frame rate. Using ffmepg (in Linux) I know I can get this information via the following command:

ffprobe -v 0 -of compact=p=0 -select_streams 0 -show_entries stream=r_frame_rate 'MyVideoFIle.mp4'

Which returns:

r_frame_rate=24000/1001

FFmpex

Doing this in bash is fine, but what I really want is to use it in my Elixir application. To this end I found out about ffmpex.

First I tried using FFprobe:

> FFprobe.format("Devil May Cry 5 Bury the Light LITTLE V COVER.mp4")

{:ok,
 %{
   "bit_rate" => "611784",
   "duration" => "482.999000",
   "filename" => "Devil May Cry 5 Bury the Light LITTLE V COVER.mp4",
   "format_long_name" => "QuickTime / MOV",
   "format_name" => "mov,mp4,m4a,3gp,3g2,mj2",
   "nb_programs" => 0,
   "nb_streams" => 2,
   "probe_score" => 100, 
   "size" => "36936415",
   "start_time" => "0.000000",
   "tags" => %{
     "compatible_brands" => "isomiso2avc1mp41",
     "encoder" => "Lavf58.19.102",
     "major_brand" => "isom",
     "minor_version" => "512"
   }
 }}

Which gives me some information, but not the frame rate.

My next tentative was to use the command options:

command = 
  FFmpex.new_command() 
  |> add_input_file("Devil May Cry 5 Bury the Light LITTLE V COVER.mp4") 
  |> add_video_option(???) 

But the problem here is that I can't find in the documentation the video option I need to get the native frame rate. I only found vframe which is used to set the video frame rate.

Question

  • How can I get the native fps of a video using ffmpex?
2 Answers

By following @VC.One's suggestion and checking the source code, I was able to find FFprobe.streams("filename").

This function will return a list of streams with their avg_frame_rate, which is what the native command from the shell was doing:

FFprobe.streams("Devil May Cry 5 Bury the Light LITTLE V COVER.mp4")
{:ok,
 [
   %{
     "refs" => 1,
     "avg_frame_rate" => "24000/1001",
     "level" => 31,
     "nb_frames" => "11579",
     "is_avc" => "true",
     "coded_height" => 720,
     "index" => 0,
     "display_aspect_ratio" => "16:9",
     "r_frame_rate" => "24000/1001",
     "nal_length_size" => "4",
     "has_b_frames" => 1,
     "height" => 720,
     "time_base" => "1/24000",
     "codec_time_base" => "1001/48000",
     "color_transfer" => "bt709",
     "color_space" => "bt709",
     "codec_tag_string" => "avc1",
     "pix_fmt" => "yuv420p",
     "bits_per_raw_sample" => "8",
     "bit_rate" => "478071",
     "codec_tag" => "0x31637661",
     "profile" => "Main",
     "sample_aspect_ratio" => "1:1",
     "chroma_location" => "left",
     "color_primaries" => "bt709",
     "coded_width" => 1280,
     "width" => 1280,
     "codec_type" => "video",
     "codec_long_name" => "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
     "start_time" => "0.000000",
     "duration" => "482.940792",
     "duration_ts" => 11590579,
     "codec_name" => "h264",
     "start_pts" => 0,
     "tags" => %{
       "handler_name" => "ISO Media file produced by Google Inc.",
       "language" => "und"
     },
     "color_range" => "tv",
     "disposition" => %{
       "attached_pic" => 0,
       "clean_effects" => 0,
       "comment" => 0,
       "default" => 1,
       "dub" => 0,
       "forced" => 0,
       "hearing_impaired" => 0,
       "karaoke" => 0,
       "lyrics" => 0,
       "original" => 0,                                                                                                                                                                      
       ...                                                                                                                                                                                   
     }
   },
   %{
     "avg_frame_rate" => "0/0",
     "bit_rate" => "127999",
     "bits_per_sample" => 0,
     "channel_layout" => "stereo",
     "channels" => 2,
     "codec_long_name" => "AAC (Advanced Audio Coding)",
     "codec_name" => "aac",
     "codec_tag" => "0x6134706d",
     "codec_tag_string" => "mp4a",
     "codec_time_base" => "1/44100",
     "codec_type" => "audio",
     "disposition" => %{
       "attached_pic" => 0,
       "clean_effects" => 0,
       "comment" => 0,
       "default" => 1,
       "dub" => 0,
       "forced" => 0,
       "hearing_impaired" => 0,
       "karaoke" => 0,
       "lyrics" => 0,
       "original" => 0,
       "timed_thumbnails" => 0,
       "visual_impaired" => 0
     },
     "duration" => "482.998277",
     "duration_ts" => 21300224,
     "index" => 1,
     "max_bit_rate" => "127999",
     "nb_frames" => "20801",
     "profile" => "LC",
     "r_frame_rate" => "0/0",
     "sample_fmt" => "fltp",
     "sample_rate" => "44100",
     "start_pts" => 0,
     "start_time" => "0.000000",
     "tags" => %{
       "handler_name" => "ISO Media file produced by Google Inc.",
       "language" => "und"
     },
     "time_base" => "1/44100"
   }
 ]}

This answers my question. FFprobe.format/1 was never the solution, it was FFprobe.streams/1!

I don't use FFmpex but from a quick look at the source code on Github:

Seeing that line 71 of ffmpex/lib/ffprobe.ex is the one that sets the options passed on to FFprobe:

cmd_args = ["-v", "quiet", "-print_format", "json", "-show_format", file_path]

So maybe adjust that line to become as:

cmd_args = ["-v", "quiet", "-print_format", "json", "-show_format", "-show_entries stream=r_frame_rate", file_path]

It's possible the above is expected to be written as:

cmd_args = ["-v", "quiet", "-print_format", "json", "-show_format", "-show_entries", "stream=r_frame_rate", file_path]
Related