Home

GEONius.com
11-Aug-2019
E-mail

srt_util - SubRip Text (SRT) File Utilities

The SRT_UTIL package provides functions for reading, manipulating, and saving SubRip Text (SRT) subtitle files.

An SRT file is a text file containing the subtitles for a video. Each subtitle is in the following format:

    sequence #
    HH:MM:SS,LLL --> HH:MM:SS,LLL   -- Beginning and ending display times.
    first line of subtitle
    ...
    last line of subtitle
                                    -- Blank line signalling end of record.

where:

For example:

    172
    00:09:28,340 --> 00:09:30,880
    JOHN: George Harrison,
    the scouse of distinction.
    blank line

Assume an existing SRT file is to be modified. An application must (i) create an empty list of subtitles, (ii) read the subtitles from the file and add them to the list, (iii) modify the subtitles as desired, and (iv) save the list of modified subtitles to a file:

    SubtitleList  list ;

    srtListCreate (&list) ;                         -- Empty list.
    srtListLoad (list, "input file", -1) ;          -- Read file.
    ... modify the subtitles in the list ...
    srtListSave (list, "output file", -1) ;         -- Write file.
    srtDestroyList (list) ;                         -- All done!

Individual subtitles in a list can be found by sequence number with srtListFind() or by position (1..N) with srtListGet(). When chopping up a list, the sequence numbers can get out of order; regenerating a normal sequence of numbers is done with srtListRenumber().

In the case of inserting a new subtitle in an existing SRT file or adding it to a brand new SRT file, the following example (i) creates a new subtitle; (ii) sets its sequence number (1768), beginning and ending display times, and lines of text; and (iii) adds it to the end of a list like the one above:

    Subtitle  caption ;

    srtCreate (1768, &caption) ;
    srtSetTimes (caption,
                 srtStringToTime ("01:35:38,566"),
                 srtStringToTime ("01:35:40,899")) ;
    srtAddLine (caption, "There's nothing wrong with you", -1) ;
    srtAddLine (caption, "that can't be cured with a", -1) ;
    srtAddLine (caption, "little Prozac and a polo mallet.", -1) ;
    srtListAdd (list, caption, -1) ;

Attributes of a subtitle can retrieved or modified by name with srtGet() and srtSet(), respectively. A subtitle's display times can be accessed with those two functions or, more directly, with srtGetTimes() and srtSetTimes().

Synchronizing Subtitles with Audio

I wrote my subtle program and this function package for the purpose of synchronizing subtitles with a video's audio track. The program and package assume that the subtitles (i) are already synchronized, (ii) have a constant offset from the audio throughout the video, or (iii) have an offset that varies linearly with time. The SRT_UTIL package can calculate the equation of the line in the latter two cases (and the trivial first case as well).

The user must supply the offsets in seconds of two widely separated subtitles, ideally from the beginning and end of the video. The offsets are more or less easily measured by watching the video and listening for what's said in the subtitle of interest to begin being said. Pause the video immediately and compare the video's timestamp to the subtitle's beginning time. Subtract the subtitle's time from the video's time. If the difference (offset) is positive, that means the subtitle appears too early and must be delayed the given number of seconds. If the difference is negative, that means the subtitle appears too late and must be moved up by the (absolute value) number of seconds.

The following code fragment calculates the equation of the line connecting the synchronized (shifted) times of two subtitles:

    Subtitle  caption1, caption2 ;
    double  offset1, offset2, slope, yIntercept ;

    caption1 = srtListGet (list, 2) ;       -- Second subtitle.
    offset1 = 3.75 ;                        -- Observed offset.

    caption2 = srtListGet (list, -1) ;      -- Next-to-last subtitle.
    offset1 = 15.0 ;                        -- Observed offset.

    srtCalcMXB (caption1, offset 1, caption2, offset2,
                &slope, yIntercept) ;

The synchronized beginning and ending times of any subtitle in the list can be computed by substituting the unsynchronized times into the equation:

sync-time = (slope × unsync-time) + y-intercept

In the case of a constant offset throughout the video, srtCalcMXB() can be skipped altogether — the slope is simply 1 and the y-intercept is the offset.

NOTE because I get confused myself: srtCalcMXB() works with a graph that maps unsynchronized times (along the x-axis) to synchronized times (y-axis). If the subtitles are perfectly aligned with the audio, the modeled line would be a 45-degree diagonal through the origin (y = 1x + 0 = x). If the offset is constant throughout the video, there would again be a 45-degree diagonal positioned above or below the origin by the offset.

Confusion sets in for me when I offhandedly visualize the graph, as the image that immediately comes to mind is a graph of the offsets versus the uncorrected times. Thus I picture a constant offset as a horizontal line parallel to the x-axis instead of the 45-degree line whose equation srtCalcMXB() actually returns. Each approach works — I just happened to choose the synchronized times approach (which, incidentally, saves one floating-point addition when applying the equation to a raw time!).

All of the subtitles in the list can be corrected with a single call:

    srtListApplyMXB (list, slope, yIntercept) ;

Public Procedures (subtitles)

srtAddLine() - adds a line of text to a subtitle.
srtApplyMXB() - adjusts the begin and end display times of a subtitle.
srtCalcMXB() - find the line connecting the shifted times of two subtitles.
srtCheck() - checks two adjacent captions for various errors.
srtCreate() - creates a single subtitle.
srtDestroy() - destroys a subtitle.
srtDuplicate() - duplicates a subtitle.
srtGet() - gets the value of a subtitle attribute.
srtGetTimes() - gets a subtitle's beginning and ending display times.
srtReadFile() - reads a subtitle from a disk file.
srtReadString() - reads a subtitle from a string.
srtSet() - sets the value of a subtitle attribute.
srtSetTimes() - sets a subtitle's beginning and ending display times.
srtStringToTime() - converts a string to a subtitle time.
srtTimeToString() - converts a subtitle time to a string.

Public Procedures (collections)

srtListAdd() - adds/inserts a subtitle to/in a list.
srtListApplyMXB() - adjusts the times of all the subtitles in a list.
srtListCreate() - creates an empty list of subtitles.
srtListDelete() - deletes a subtitle from a list.
srtListDestroy() - destroys a list of subtitles.
srtListFind() - finds a subtitle by sequence number.
srtListGet() - retrieves a subtitle by position.
srtListLength() - returns the number of subtitles in a list.
srtListLoad() - loads subtitles from a disk file.
srtListMerge() - merges two lists into a new list.
srtListRenumber() - renumbers the subtitles in a list.
srtListSave() - saves subtitles to a disk file.

Source Files

srt_util.c
srt_util.h

Alex Measday  /  E-mail