Putting Chapter Marks into a QuickTime Movie from a Text File.

Hey folks,

I am wondering if this is even possible…can you take a list of timecodes and corresponding names and make them into chapters in QuickTime Pro?

I’ve downloaded some of the sample scripts for QT, but they don’t seem to work with timecode (only frame counts from the start of the movie). Now, additional timecode support was added in recent QuickTime but I don’t know if it extends to this.

I can do a similar thing with Compressor (using the Commandline interface to load a chapter list file ” this is new to Compressor 3.0.2 incidentally, you can see these new commands if you do a ./Compressor -help in terminal). The problem with using Compressor is that it always recompresses the file. So, even if your movie is a H.264 already, it will recompress it again and degrade the quality.

You can add chapter marks to a H.264 movie via Garageband, one by one, and then export it without changing the quality, but it is not scriptable.

So, that leaves me with QT, which is scriptable, but I don’t know if it has this capability?

A chapter list file is pretty trivial. It usually is formatted as:

01:00:00:00 Start
01:00:10:00 First Scene
01:02:50:05 First Interview
01:05:00:10 Second Interview

Has anyone tried something like this before?

Cheers.

OK, here’s what I have so far. It semi works but it fails to put in the subsequent chapter marks.

The big problem I’m seeing is how QuickTime deals with time. So, it doesn’t seem like I can use straight timecodes, so I’m trying to create durations from two timecodes and add chapters that way.

But I’m getting a little confused now. Sigh.


global theMovieName
global this_track
global theMovie
global fps




tell application "Finder"
	set these_items to (choose file with prompt "Pick the Chapter Text file to use:" & return & "The proper format the text file should have is {Timecode Chapter Name}") as list
	set theMovie to choose file with prompt "Choose the QuickTime Movie you want to Chapterize:"
	
	set theMovieName to the name of (info for theMovie)
	set fps to 30
end tell


OpenMovie(theMovie)

open these_items
end


on open these_items
	try
		
		
		
		
		set this_data to read (item 1 of these_items)
		
		set this_data to parseTXT(this_data)
	end try
	
	
	
	
	
	
end open

on OpenMovie(theMovie)
	
	tell application "QuickTime Player"
		
		open theMovie
	end tell
	try
		
		tell application "QuickTime Player" to tell front document
			
			set these_tracks to the name of every track
			if these_tracks contains "Chapter Track" then
				tell application "Finder"
					display dialog "This movie already has a Chapter Track" & return & "Do you want to delete the track and create a new one?" buttons {"Yes", "No"}
					if button returned of the result is "No" then error number -128
				end tell
				delete track "Chapter Track"
			end if
			
		end tell
	end try
	
end OpenMovie

on parseTXT(this_data)
	
	
	repeat with i from 1 to the count of paragraphs in this_data
		set this_line to paragraph i of this_data
		set theTimecode to trim_line(characters 1 thru 11 of this_line as string, " ", 2)
		set theChapter to trim_line(characters 13 thru -1 of this_line as string, " ", 2)
		set the chapterInfo to {}
		set the end of chapterInfo to theTimecode
		set the end of chapterInfo to theChapter
		
		
		tell application "QuickTime Player"
			
			
			tell front document
				
				if i is equal to 1 then
					set this_track to make new track at beginning with data theChapter
					set enabled of this_track to false
					set the name of this_track to "Chapter Track"
					set chapterlist of track 1 to track "Chapter Track"
					set the movie_length to the duration
					set firstTime to theTimecode
					tell chapter 1
						set the time to 0
						set the duration to movie_length
					end tell
				else
					set nextTime to theTimecode
					set newmovielengthframes to ((my convert_frame_string_to_number(firstTime)) + (my convert_frame_string_to_number(nextTime)))
					set newmovielength to my convert_number_to_frame_string(newmovielengthframes)
					set the newmovielength to the duration
					set the duration of this_track to newmovielength
					set the chapter_list to the name of every chapter
					set the new_chapter_list to chapter_list & (i as string)
					set the contents of the current chapter track to the new_chapter_list
					set the time of chapter i to movie_length
					set the duration of chapter i to newmovielength - movie_length
					set the name of chapter i of this_track to theChapter
					set movie_length to the duration
					set firstTime to convert_frame_string_to_number(theTimecode)
				end if
			end tell
			
			
			
		end tell
	end repeat
	
end parseTXT


on trim_line(this_text, trim_chars, trim_indicator)
	-- 0 = beginning, 1 = end, 2 = both
	set x to the length of the trim_chars
	-- TRIM BEGINNING
	if the trim_indicator is in {0, 2} then
		repeat while this_text begins with the trim_chars
			try
				set this_text to characters (x + 1) thru -1 of this_text as string
			on error
				-- the text contains nothing but the trim characters
				return ""
			end try
		end repeat
	end if
	-- TRIM ENDING
	if the trim_indicator is in {1, 2} then
		repeat while this_text ends with the trim_chars
			try
				set this_text to characters 1 thru -(x + 1) of this_text as string
			on error
				-- the text contains nothing but the trim characters
				return ""
			end try
		end repeat
	end if
	return this_text
end trim_line

on parse_text(this_text, open_tag, close_tag)
	set x to the offset of the open_tag in this_text
	if x is 0 then return "NO TAG"
	set this_text to (characters (x + (length of the open_tag)) thru -1 of this_text) as string
	set x to the offset of the close_tag in this_text
	if x is 1 then
		return "NO DATA"
	else
		set this_text to (characters 1 thru (x - 1) of this_text) as string
	end if
	return this_text
end parse_text


on convert_frame_string_to_number(the_string)
	tell (a reference to my text item delimiters)
		set {old_delim, contents} to {contents, ":"}
		set {{h, m, s, f}, contents} to {the_string's text items, old_delim}
	end tell
	set h to (h as integer) * fps * hours
	set m to (m as integer) * fps * minutes
	set s to (s as integer) * fps
	return h + m + s + f
end convert_frame_string_to_number

on convert_number_to_frame_string(the_number)
	set h to ("0" & (the_number div (fps * hours)))'s text -2 thru -1
	set m to ("0" & ((the_number mod (fps * hours)) div (fps * minutes)))'s text -2 thru -1
	set s to ("0" & (the_number mod (fps * minutes)) div fps)'s text -2 thru -1
	set f to ("0" & (the_number mod fps))'s text -2 thru -1
	return "" & {h, ":", m, ":", s, ":", f}
end convert_number_to_frame_string