2 This file is part of the HandBrake source code.
3 Homepage: <http://handbrake.fr/>.
4 It may be used under the terms of the GNU General Public License. */
13 struct start_and_end {
14 unsigned long start, end;
20 k_state_potential_new_entry,
24 typedef struct srt_entry_s {
25 long offset, duration;
31 * Store all context in the work private struct,
33 struct hb_work_private_s
37 unsigned long current_time;
38 unsigned long number_of_entries;
39 unsigned long current_state;
40 srt_entry_t current_entry;
41 iconv_t *iconv_context;
42 hb_subtitle_t *subtitle;
43 uint64_t start_time; // In HB time
44 uint64_t stop_time; // In HB time
47 static struct start_and_end read_time_from_string( const char* timeString )
49 // for ex. 00:00:15,248 --> 00:00:16,545
51 long houres1, minutes1, seconds1, milliseconds1,
52 houres2, minutes2, seconds2, milliseconds2;
54 sscanf(timeString, "%ld:%ld:%ld,%ld --> %ld:%ld:%ld,%ld\n", &houres1, &minutes1, &seconds1, &milliseconds1,
55 &houres2, &minutes2, &seconds2, &milliseconds2);
57 struct start_and_end result = {
58 milliseconds1 + seconds1*1000 + minutes1*60*1000 + houres1*60*60*1000,
59 milliseconds2 + seconds2*1000 + minutes2*60*1000 + houres2*60*60*1000};
64 * Read the SRT file and put the entries into the subtitle fifo for all to read
66 static hb_buffer_t *srt_read( hb_work_private_t *pv )
69 char line_buffer[1024];
76 while( fgets( line_buffer, sizeof( line_buffer ), pv->file ) )
78 switch (pv->current_state)
80 case k_state_timecode:
82 struct start_and_end timing = read_time_from_string( line_buffer );
83 pv->current_entry.duration = timing.end - timing.start;
84 pv->current_entry.offset = timing.start - pv->current_time;
86 pv->current_time = timing.end;
88 pv->current_entry.start = timing.start;
89 pv->current_entry.stop = timing.end;
91 pv->current_state = k_state_inEntry;
102 // If the current line is empty, we assume this is the
103 // seperation betwene two entries. In case we are wrong,
104 // the mistake is corrected in the next state.
105 if (strcmp(line_buffer, "\n") == 0 || strcmp(line_buffer, "\r\n") == 0) {
106 pv->current_state = k_state_potential_new_entry;
111 for( q = pv->current_entry.text; (q < pv->current_entry.text+1024) && *q; q++);
115 in_size = strlen(line_buffer);
116 out_size = (pv->current_entry.text+1024) - q;
118 retval = iconv( pv->iconv_context, &p, &in_size, &q, &out_size);
121 if( ( retval == -1 ) && ( errno == EINVAL ) )
123 hb_error( "Invalid shift sequence" );
124 } else if ( ( retval == -1 ) && ( errno == EILSEQ ) )
126 hb_error( "Invalid byte for codeset in input, %d bytes discarded",
128 } else if ( ( retval == -1 ) && ( errno == E2BIG ) )
130 hb_error( "Not enough space in output buffer");
136 case k_state_potential_new_entry:
138 const char endpoint[] = "\0";
139 const unsigned long potential_entry_number = strtol(line_buffer, (char**)&endpoint, 10);
140 hb_buffer_t *buffer = NULL;
142 * Is this really new next entry begin?
144 if (potential_entry_number == pv->number_of_entries + 1) {
146 * We found the next entry - or a really rare error condition
148 if( *pv->current_entry.text )
152 uint64_t start_time = ( pv->current_entry.start +
153 pv->subtitle->config.offset ) * 90;
154 uint64_t stop_time = ( pv->current_entry.stop +
155 pv->subtitle->config.offset ) * 90;
157 if( !( start_time > pv->start_time && stop_time < pv->stop_time ) )
159 hb_deep_log( 3, "Discarding SRT at time start %lld, stop %lld", start_time, stop_time);
160 memset( &pv->current_entry, 0, sizeof( srt_entry_t ) );
161 ++(pv->number_of_entries);
162 pv->current_state = k_state_timecode;
166 length = strlen( pv->current_entry.text );
168 for( p = pv->current_entry.text; *p; p++)
170 if( *p == '\n' || *p == '\r' )
176 buffer = hb_buffer_init( length + 1 );
180 buffer->start = start_time - pv->start_time;
181 buffer->stop = stop_time - pv->start_time;
183 memcpy( buffer->data, pv->current_entry.text, length + 1 );
186 memset( &pv->current_entry, 0, sizeof( srt_entry_t ) );
187 ++(pv->number_of_entries);
188 pv->current_state = k_state_timecode;
196 * Well.. looks like we are in the wrong mode.. lets add the
197 * newline we misinterpreted...
199 strncat(pv->current_entry.text, " ", 1024);
200 pv->current_state = k_state_inEntry;
211 static int decsrtInit( hb_work_object_t * w, hb_job_t * job )
214 hb_work_private_t * pv;
217 hb_chapter_t * chapter;
218 hb_title_t *title = job->title;
220 pv = calloc( 1, sizeof( hb_work_private_t ) );
223 w->private_data = pv;
227 buffer = hb_buffer_init( 0 );
228 hb_fifo_push( w->fifo_in, buffer);
230 pv->file = fopen( w->subtitle->config.src_filename, "r" );
232 pv->current_state = k_state_potential_new_entry;
233 pv->number_of_entries = 0;
234 pv->current_time = 0;
235 pv->subtitle = w->subtitle;
238 * Figure out the start and stop times from teh chapters being
239 * encoded - drop subtitle not in this range.
242 for( i = 1; i < job->chapter_start; ++i )
244 chapter = hb_list_item( title->list_chapter, i - 1 );
247 pv->start_time += chapter->duration;
249 hb_error( "Could not locate chapter %d for SRT start time", i );
253 chapter = hb_list_item( title->list_chapter, i - 1 );
257 pv->stop_time = pv->start_time + chapter->duration;
259 hb_error( "Could not locate chapter %d for SRT stop time", i );
263 hb_deep_log( 3, "SRT Start time %lld, stop time %lld", pv->start_time, pv->stop_time);
265 pv->iconv_context = iconv_open( "utf8", pv->subtitle->config.src_codeset );
268 if( pv->iconv_context == (iconv_t) -1 )
270 hb_error("Could not open the iconv library with those file formats\n");
273 memset( &pv->current_entry, 0, sizeof( srt_entry_t ) );
275 pv->file = fopen( w->subtitle->config.src_filename, "r" );
279 hb_error("Could not open the SRT subtitle file '%s'\n",
280 w->subtitle->config.src_filename);
290 static int decsrtWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
291 hb_buffer_t ** buf_out )
293 hb_work_private_t * pv = w->private_data;
294 hb_buffer_t * in = *buf_in;
295 hb_buffer_t * out = NULL;
297 out = srt_read( pv );
302 * Keep a buffer in our input fifo so that we get run.
304 hb_fifo_push( w->fifo_in, in);
308 printf("\nSRT Done\n");
316 static void decsrtClose( hb_work_object_t * w )
318 hb_work_private_t * pv = w->private_data;
320 iconv_close(pv->iconv_context);
321 free( w->private_data );
324 hb_work_object_t hb_decsrtsub =
327 "SRT Subtitle Decoder",