QTKit, QTStringTime() and SMPTE

QTKit is quite convenient, but strangely only after Mac OS X 10.5, SMPTE style timecode getter was added as SMPTETimeValue() as a function in NSValue_QTKitAdditions.

So, if you want to write codes for Mac OS X 10.4 or 10.3 as minimum requirement, you should write your own. ( People tend to use classes and messages available only on Mac OS X 10.5 nowadays, but why? 10.4 is still popular! )

However, we have one problem. Let’s read explanation about the QTStringTime().

QTKIT_EXTERN NSString * QTStringFromTime (QTTime time);
Discussion
This function returns a description of a QTTime structure. The string is in the form “sign:days:hours:minutes:seconds:timevalue:timescale

What is the timescale? Is it second, minute, or hour? What is timevalue? Is it remainder smaller than second? There is no clear explanation. Example of the QuickTime time format is :

  1. 0:00:00:01:20:11/3000
  2. 0:00:00:01:20:1120/2997

I could confirm it using the QTKitPlayer sample code. The QuickTime player is worse than the QTKitPlayer in displaying the time code. The QuickTime player doesn’t display the timevalue:timescale part. And the Final Cut Pro displays SMPTE instead of the QuickTime time format.

So, I could easily determine that the number after / represents fps * 100. For example, 2997 is 29.97. At first I though that 11/3000 is, for example, is 11 divided by 3000. But it turned out that it is ….11 and the timescale used is 3000. It is also weird that fps is called, “timescale”.
Why doesn’t Apple use more understandable term?

Anyway.. from definition of QTTime :

typedef struct {
	long long		timeValue;
	long			timeScale;
	long			flags;
} QTTime;

timeValue % timeScale is “frames”.
timeValue / timeScale is second
. And if you divide the second with 60, the remainder is second, and its quotient is minute, and so on.

So, I could find out that timeValue is number of frames. So, the term “timeValue” is misleading.

Comment in QTTime.h is more accurate than the documentation.

// dd:hh:mm:ss.ff/ts
QTKIT_EXTERN NSString *QTStringFromTime (QTTime time)

Now, how about the “frame” that is remainder of the above calculation, timeValue % timeScale? It is like 1120 in the example 2 above. Is it really 1120 frames? No.
Just like that 2997 is 29.97 *100, 1120 is also 11.20 * 100. So, rouding 1120 gives correct “frame” value for the SMPTE style.

So, the QTTime format can be easily converted to SMPTE style.
What is the SMPTE style? It is : hh:mm:ss:ff

So, my ugly completed code is :

NSString *SMPTEStringFromTime( QTTime time )
{
	NSString *SMPTE_string;
	int days, hour, minute, second, frame;
	long long result;

	// timeScale is fps * 100
	result = time.timeValue / time.timeScale; // second
	frame = (time.timeValue % time.timeScale) / 100;

	second = result % 60;

	result = result / 60; // minute
	minute = result % 60;

	result = result / 60; // hour
	hour = result % 24;

	days = result;

	SMPTE_string = [NSString stringWithFormat:@"%02d:%02d:%02d:%02d", hour, minute, second, frame]; // hh:mm:ss:ff

	return SMPTE_string;
}

10 responses to this post.

  1. Posted by Onotoley on October 13, 2011 at 5:01 PM

    You might find this one insightful: http://videogorillas.com/?p=14

    Reply

  2. Posted by David Johns on June 2, 2013 at 2:47 PM

    Know this is old, but just was researching this subject and found this helpful post still shedding some light. Just noticed that timescale doesn’t always have to be fps * 100. Seems a safer calculation for frames is:

    frame = (time.timeValue % time.timeScale) / time.timeScale * 29.97;

    when TimeScale is 2997 then you get the /100 in the original code. If timeScale is something weird, dividing the left over timevalues (which will be in units of the timescale) gives a leftover time in fractions of a second and multiplying by 29.97 gives the smpte drop code number of frames.

    Should do it as floating point of course:

    frame = (int)((double)(time.timeValue % time.timeScale)/(double)time.timeScale * 29.97);

    Reply

    • Posted by jongampark on June 2, 2013 at 4:16 PM

      @David Johns
      As you pointed out, the timescale doesn’t need to be fps*100. When I checked timescale and related field in various headers in mov format, I noticed one day that even Apple used some inconvenient value when I created a movie file using Final Cut Pro. However, although I don’t remember the exact number they used, Apple people cleverly chose a number which can minimize the error between floating/double number and integer number.

      So, yes. you can even choose some other value for that.

      I’m glad that there are people who are interested in this stuff in the area of *.mov.
      Even Apple’s document was not written to help people to understand it easily, although the topic is very straightforward and easy one, but their explanation was somewhat vague and if one really need to drill down, their documentation didn’t really help, although it can give some clue.

      Thanks again,

      Happy programming!

      Reply

Leave a comment