0

I'm working on a Python script to bulk transcode video files. These files will have different framerates, and one of the goals is to get them all to the same framerate, by making some intelligent decisions on whether to slow down or speed up the playback or to decimate or duplicate frames. As I understand it, the framerate is stored as two 32-bit integers, for example 29.97 fps is actually stored as 30000/1001, and I need to work with these values. I'll also use these values to calculate how much to stretch and pitch shift the audio. The framerates of the source files are not necessarily standard ones, but they may be anything from slightly off from PAL or NTSC to completely screwed up, and using the values that are actually in the files makes it easier to make the calculations.

So, how can I extract them, and, in the case of slowing down or speeding up the video, write back modified values?
Preferably a commandline tool (needs to run on FreeBSD).
I'm also open to parsing the headers directly from the script, but unfortunately I don't know where to find them.

The specs I've found more or less list the various structs (as defined in C) for the various headers, and a more skilled programmer may be able to use this, but I need a simpler explanation. I don't need help with the actual scripting, I just need help understanding where the information is located.


OpenDML AVI File Format Extensions
AVI File Format

  • What tool will you use to transcode? – Gyan Dec 24 '16 at 12:07
  • @Mulvya I will be using ffmpeg – user17556 Dec 24 '16 at 12:13
  • Then you are all set. Just set a -r N and ffmpeg will duplicate or decimate as required. In any case, you can get framerate from ffprobe. – Gyan Dec 24 '16 at 12:16
  • @Mulvya I know ffprobe, and it doesn't give me the info I need. As an example I got this from a file: 23.98 fps, 23.98 tbr, 23.98 tbn, 23.98 tbc. I need to get the 24000 and 1001 from that. And for a standard framerate like this, it's pretty easy to deduce, but the source may have practially any framerate, like 21.749128. – user17556 Dec 24 '16 at 12:27
  • You need to query for stream entries i.e. ffprobe in.avi -show_entries stream=r_frame_rate,avg_frame_rate -select_streams v -v 0 -of compact=p=0:nk=1 The first rational value is from the stream header; the 2nd is the computed value which will differ for a variable frame rate stream. – Gyan Dec 24 '16 at 12:35
0

ffprobe can supply the frame rate as a rational value

ffprobe in.avi -show_entries stream=r_frame_rate,avg_frame_rate -select_streams v -v 0 -of compact=p=0:nk=1

The first rational value is from the stream header; the 2nd is the computed value which will differ for a variable frame rate stream

| improve this answer | |
  • Seems I got a bit excited, and this was only half the solution. In the cases where I let the script decide to slow down or speed up the video, rather than decimate/duplicate frames, I also need to modify the fps without modifying the stream, but I found that ffmpeg can handle these cases too. E.g. slow down from 25 to 23.98: ffmpeg -i in.avi -r 24000/1001 filter:v "setpts=1001/960*PTS" out.avi. I was afraid that this would first drop some frames, then duplicate some of the remaining ones, but in the tests I've done, it seems to just modify the fps, then transcode the original frames. – user17556 Dec 25 '16 at 2:27
  • It is the encoder which drops or dupes frames based on the frame rate required. It does this by looking at the PTS series. Since the setpts filter is being used, it is getting the expected number of frames. Had your setpts argument been different but the same r value: e.g. PTS*2002/960 then you see frames being added. – Gyan Dec 25 '16 at 4:57
  • Good to know. Thanks. I'll even throw in a Merry Christmas. :) – user17556 Dec 25 '16 at 4:59
  • Happy Holidays to you too. – Gyan Dec 25 '16 at 4:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy