Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have a video file and I want to get the number of video frames that are in it. I can use ffmpeg to get the length of the video and the FPS. However I can't see anything obvious for the total number of frames.

In theory one should be able to multiply the length (in seconds) by the FPS to get the number of frames, but in this case the length (34.43 seconds) and the framerate (29.97 fps) give a non-integer, which makes me think I'm doing something wrong.

I need to be able to do this on the command line in a totally automated and non-graphical manner. I also need this to be pretty exact, and not an estimate (if that's even possible with video files)

I tried using tcprobe on some files. For some AVI files it works, but for some VOB files, the tcprobe output doesn't have the number of frames. I get this output:

[tcprobe] MPEG program stream (PS)
[tcprobe] summary for myfile.vob, (*) = not default, 0 = not detected
import frame size: -g 720x480 [720x576] (*)
     aspect ratio: 4:3 (*)
       frame rate: -f 29.970 [25.000] frc=4 (*)
                   PTS=2199.3972, frame_time=33ms bitrate=7000 kbps
      audio track: -a 0 [0] -e 48000,16,5 [48000,16,2] -n 0x2000 [0x2000] (*)
                   PTS=2199.2763, bitrate=192 kbps
                   -D 3 --av_fine_ms 20 (frames & ms) [0] [0]
share|improve this question
    
your equation will give you a good ballpark estimate; just round the floating-pt result up. if you need an exact number of frames you'll need to examine the file directly -- your estimate might be off by one or two in either direction due to the particulars of the video codec. –  quack quixote Dec 17 '09 at 18:47
    
are these all-in-one-file VOBs or DVD-style split-into-multiple-file VOBs? –  quack quixote Dec 18 '09 at 16:55
add comment

5 Answers

up vote 4 down vote accepted

This is horrible, and stupid, and slow, but seems to work:

ffmpeg -i foo.avi -vcodec copy -f rawvideo -y /dev/null 2>&1 | tr ^M '\n' | awk '/^frame=/ {print $2}'|tail -n 1

It will also work right on truncated files and raw streams(that is why you get nothing for .vob files)

share|improve this answer
    
That's pretty good. In my experience, it doesn't take that long. A 40 minute file takes about <3seconds to run though. Remember that the "^M" is not the 2 characters ^ and M, you have to press Control-V, and then enter. Instead of your command I used: ffmpeg -i somefile.avi -vcodec copy -f rawvideo -y /dev/null 2>&1 | tr "^M" '\n' | grep '^frame=' | perl -pe 's/^frame=\s*([0-9]+)\s.*$/\1/' | tail -n 1 Your command fails if there's no space after the "frames=" –  Rory Jan 5 '10 at 12:23
add comment

I posted this on another question. Using the tcprobe tool (from the transcode package), the number of frames is included in the info. Use the -i switch to get an info dump from the file:

$ tcprobe -i foo.avi
[tcprobe] RIFF data, AVI video
[avilib] V: 29.970 fps, codec=XVID, frames=38630, width=512, height=384
[avilib] A: 48000 Hz, format=0x55, bits=16, channels=2, bitrate=128 kbps,
[avilib]    53707 chunks, 21768720 bytes, VBR
[tcprobe] summary for foo.avi, (*) = not default, 0 = not detected
import frame size: -g 512x384 [720x576] (*)
       frame rate: -f 29.970 [25.000] frc=4 (*)
      audio track: -a 0 [0] -e 48000,16,2 [48000,16,2] -n 0x55 [0x2000] (*)
                   bitrate=128 kbps
           length: 38630 frames, frame_time=33 msec, duration=0:21:28.954

Note the number of frames is given on two lines here (2nd output line and last output line).

share|improve this answer
    
That looks like a good answer, and works for some files, but for some VOB files I have, I don't have that data in the output. I've updated the question with the output I get –  Rory Dec 18 '09 at 9:58
    
i expect (but don't know for sure) that tcprobe is examining file headers for this info. if it's not included in the header, tcprobe may not attempt a calculation for it. good question; wish i had a good answer for you. –  quack quixote Feb 3 '10 at 7:59
add comment

ffprobe can be used to get info about a media file:

ffprobe -select_streams v -show_streams input.avi

You will get details about the stream:

nb_frames=159697

Look for nb_frames with grep:

ffprobe -select_streams v -show_streams input.avi 2>/dev/null | grep nb_frames | sed -e 's/nb_frames=//'

That works for avi, mp4 and etc For some containers, it does not show valid value e.g. mpeg.

In that case, this works ffprobe -show_packets a.mpg 2>/dev/null | grep video | wc -l

share|improve this answer
    
Good idea. I modified the command a little so that it only selects the video stream, and filters the output. That gives you just the number of frames. –  slhck Jun 13 at 14:31
add comment

I've found that the number of frames is actually twice the fps*duration (no idea why, I'd be happy know).

In a script of mine, I have:

# Get duration and fps
duration=$($FFMPEG -i $input 2>&1 | sed -n "s/.* Duration: \([^,]*\), start: .*/\1/p")
fps=$($FFMPEG -i $input 2>&1 | sed -n "s/.*, \(.*\) tb.*/\1/p")

hours=$(echo $duration | cut -d":" -f1)
minutes=$(echo $duration | cut -d":" -f2)
seconds=$(echo $duration | cut -d":" -f3)
# For some reason, we have to multiply by two (no idea why...)
# Get the integer part with cut
frames=$(echo "($hours*3600+$minutes*60+$seconds)*$fps*2" | bc | cut -d"." -f1)

And yes, for some reason I have to get the integer part of it. It doesn't make sense, but this script has always managed to convert my videos properly so far.

share|improve this answer
    
Because FPS stands for Frames Per Second (or first person shooter :D ) and if there's 30 FPS simply multiply it by how many seconds are in the video. –  John T Dec 17 '09 at 16:38
    
Yes John, I could figure that out, but that doesn't explain why I have to multiply it by 2 to get the right amount of frames... In my case, after I calculated the amount of frames, I launched ffmpeg in the background and analyzed the logs to make a progress bar. The logs show how many frames have passed in the conversion. Once the whole video was converted, the frame # was int(seconds*fps*2), hence my code, but I'd like to know why ;-) –  ℝaphink Dec 17 '09 at 17:08
    
that's curious; the tcprobe output in my answer gives the # of frames as exactly seconds*fps (rounded up). i expect you're seeing a quirk of ffmpeg. have you tried analyzing the file with other tools to see if they show the same number of frames? –  quack quixote Dec 17 '09 at 17:34
    
Hmmm... Interesting. I tried on a video and I got seconds*fps=1001.59 and tcprobe=1002. So obviously, tcprobe tells me I don't need to multiply by two. Why then does ffmpeg give me a number that is twice as big in the logs when it's converting? –  ℝaphink Dec 17 '09 at 17:55
    
you're watching output during encoding, not examining a file post-encode, right? could be a bug in the output code. could be something in the encoding process such that that output makes sense. i expect you'd have to examine the code to figure it out for sure. –  quack quixote Dec 17 '09 at 18:44
show 3 more comments

You can do this by adding and multiplying the values you get from ffprobe .

Note: ffprobe is part of libav(avconv) - the linux version of ffmpeg.

#your command -
 ffprobe man.avi

When you do this you will get the number of frames per/second and also the duration of the clip.

Convert the duration of the clip to second's and the multiply that value by the number of frames/second.

Remember to round up number to the nearest.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.