In a few moments in this post, I’m going to include some pseudocode for converting between drop frame timecode and a frame number and vice versa, regardless of framerate. You can skip to that if you want. Or, stay tuned for a little bit of background info. Either way, click through the jump…

I’ve been working on a program recently that will hopefully be posted soon that deals with timecode and Quicktime movies. Specifically, adding timecode tracks and doing timecode addition and subtraction. In order to do this, you need to convert the timecode, which is in an hours:minutes:seconds:frames format into a number representing the total number of frames, do your math with frame numbers, and convert back to the timecode format. For non-drop frame timecode, this is trivial. It gets complicated when you’re dealing with drop frame timecode. If you don’t know what that is, it’s a way of accurately measuring the running time of video that doesn’t run at an even frame rate. In America, video runs at 29.97 frames per second, but we usually count it at 30 fps. This means after a while, the number we use to count is wrong. The solution to this problem is drop frame timecode, which is sort of like leap year for timecode. At 29.97 fps, every minute (except ones divisible by ten), you skip counting the first two frames. You know you’re looking at drop frame timecode because the colon between minutes and frames is usually replaced by a semicolon. For example, you go:

12:38:59;27
12:38:59;27
12:38:59;28
12:38:59;29
and then you skip to…
12:39:00;02
12:39:00;03

It’s pretty difficult to calculate all of this if you’re given a frame number, or to calculate a frame number if you’re given this. After a lot of searching, I’ve only been able to come up with one website that sets out a formula for how to calculate this, Andrew Duncan’s excellent timecode page. The code I’m about to post is more or less borrowed straight from that site (with Andrew’s permission). I’m really making only two changes. First, I’m expanding a couple steps to make it a little more like a computer program, and second, I’m generalizing it so it can calculate drop frame timecode regardless of the frame rate. Andrew’s site does 29.97 drop frame only, but you can also have drop frame timecode for 59.94 and even 23.976 (although I don’t believe it’s part of the SMPTE spec and I know Final Cut doesn’t support 24p DF). For 59.94DF, you drop the first four frames per minute. And with 23.976, you drop the first two like in 29.97. So, what I’m presenting here are basically Andrew’s formulas, fleshed out a little bit, and generalized to other frame rates. It’s worth mentioning also that Quicktime has a bug when it comes to dealing with 59.94 DF timecode. In my next post, I’ll explain how to work around that bug. So, without further ado, here’s some pseudocode in a vaguely Java style. First, we’ll convert a frame number into hours, minutes, seconds, and frames [This code has been updated on 8/8/2010 to correct a bug on line 27 caught by Jean-Baptiste Mardelle of Kdenlive]:

 

  1. //CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE
  2. //Code by David Heidelberger, adapted from Andrew Duncan
  3. //Given an int called framenumber and a double called framerate
  4. //Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off.
  5.  
  6. int d;
  7. int m;
  8.  
  9. int dropFrames = round(framerate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
  10. int framesPerHour = round(framerate*60*60); //Number of frames in an hour
  11. int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours
  12. int framesPer10Minutes = round(framerate * 60 * 10); //Number of frames per ten minutes
  13. int framesPerMinute = round(framerate)*60)-  dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
  14.  
  15. if (framenumber<0) //Negative time. Add 24 hours.
  16. {
  17.     framenumber=framesPer24Hours+framenumber;
  18. }
  19.  
  20. //If framenumber is greater than 24 hrs, next operation will rollover clock
  21. framenumber = framenumber % framesPer24Hours; //% is the modulus operator, which returns a remainder. a % b = the remainder of a/b
  22.  
  23. d = framenumber\framesPer10Minutes; // \ means integer division, which is a/b without a remainder. Some languages you could use floor(a/b)
  24. m = framenumber % framesPer10Minutes
  25.  
  26. //In the original post, the next line read m>1, which only worked for 29.97. Jean-Baptiste Mardelle correctly pointed out that m should be compared to dropFrames.
  27. if (m>dropFrames)
  28. {
  29.     framenumber=framenumber + (dropFrames*9*d) + dropFrames*((m-dropFrames)\framesPerMinute);
  30. }
  31. else
  32. {
  33.     framenumber = framenumber + dropFrames*9*d;
  34. }
  35.  
  36. int frRound = round(framerate);
  37. int frames = framenumber % frRound;
  38. int seconds = (framenumber \ frRound) % 60;
  39. int minutes = ((framenumber \ frRound) \ 60) % 60;
  40. int hours = (((framenumber \ frRound) \ 60) \ 60);

 

And here’s the code to convert drop frame timecode to a frame number:

 

  1. //CONVERT DROP FRAME TIMECODE TO A FRAME NUMBER
  2. //Code by David Heidelberger, adapted from Andrew Duncan
  3. //Given ints called hours, minutes, seconds, frames, and a double called framerate
  4.  
  5. int dropFrames = round(framerate*.066666); //Number of drop frames is 6% of framerate rounded to nearest integer
  6. int timeBase = round(framerate); //We don’t need the exact framerate anymore, we just need it rounded to nearest integer
  7.  
  8. int hourFrames = timeBase*60*60; //Number of frames per hour (non-drop)
  9. int minuteFrames = timebase*60; //Number of frames per minute (non-drop)
  10. int totalMinutes = (60*hours) + minutes; //Total number of minuts
  11. int frameNumber = ((hourFrames * hours) + (minuteFrames * minutes) + (timeBase * seconds) + frames) - (dropFrames * (totalMinutes - (totalMinutes \ 10)));
  12. return frameNumber;

 

And that’s it for this entry. In a post to hopefully come in the near future, I’ll talk about the horrible quicktime 59.94 drop frame bug and how to get around it.