diff options
author | eddyg <[email protected]> | 2009-06-23 19:32:39 +0000 |
---|---|---|
committer | eddyg <[email protected]> | 2009-06-23 19:32:39 +0000 |
commit | 75545419c8d15ac244cfde51c96228870794e588 (patch) | |
tree | a0f33e05e41877fbe0fa26d3adcc1309675296b5 | |
parent | e167e96df448458160167cd0403889059c562d58 (diff) |
CLI: Missed file from SubRip - a symptom of too many views and patches
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2604 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | libhb/decsrtsub.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/libhb/decsrtsub.c b/libhb/decsrtsub.c new file mode 100644 index 000000000..190c2df80 --- /dev/null +++ b/libhb/decsrtsub.c @@ -0,0 +1,331 @@ +/* + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <iconv.h> +#include <errno.h> +#include "hb.h" + +struct start_and_end { + unsigned long start, end; +}; + +enum +{ + k_state_inEntry, + k_state_potential_new_entry, + k_state_timecode, +}; + +typedef struct srt_entry_s { + long offset, duration; + long start, stop; + char text[1024]; +} srt_entry_t; + +/* + * Store all context in the work private struct, + */ +struct hb_work_private_s +{ + hb_job_t *job; + FILE *file; + unsigned long current_time; + unsigned long number_of_entries; + unsigned long current_state; + srt_entry_t current_entry; + iconv_t *iconv_context; + hb_subtitle_t *subtitle; + uint64_t start_time; // In HB time + uint64_t stop_time; // In HB time +}; + +static struct start_and_end read_time_from_string( const char* timeString ) +{ + // for ex. 00:00:15,248 --> 00:00:16,545 + + long houres1, minutes1, seconds1, milliseconds1, + houres2, minutes2, seconds2, milliseconds2; + + sscanf(timeString, "%ld:%ld:%ld,%ld --> %ld:%ld:%ld,%ld\n", &houres1, &minutes1, &seconds1, &milliseconds1, + &houres2, &minutes2, &seconds2, &milliseconds2); + + struct start_and_end result = { + milliseconds1 + seconds1*1000 + minutes1*60*1000 + houres1*60*60*1000, + milliseconds2 + seconds2*1000 + minutes2*60*1000 + houres2*60*60*1000}; + return result; +} + +/* + * Read the SRT file and put the entries into the subtitle fifo for all to read + */ +static hb_buffer_t *srt_read( hb_work_private_t *pv ) +{ + + char line_buffer[1024]; + + if( !pv->file ) + { + return NULL; + } + + while( fgets( line_buffer, sizeof( line_buffer ), pv->file ) ) + { + switch (pv->current_state) + { + case k_state_timecode: + { + struct start_and_end timing = read_time_from_string( line_buffer ); + pv->current_entry.duration = timing.end - timing.start; + pv->current_entry.offset = timing.start - pv->current_time; + + pv->current_time = timing.end; + + pv->current_entry.start = timing.start; + pv->current_entry.stop = timing.end; + + pv->current_state = k_state_inEntry; + continue; + } + + case k_state_inEntry: + { + char *p, *q; + size_t in_size; + size_t out_size; + size_t retval; + + // If the current line is empty, we assume this is the + // seperation betwene two entries. In case we are wrong, + // the mistake is corrected in the next state. + if (strcmp(line_buffer, "\n") == 0 || strcmp(line_buffer, "\r\n") == 0) { + pv->current_state = k_state_potential_new_entry; + continue; + } + + + for( q = pv->current_entry.text; (q < pv->current_entry.text+1024) && *q; q++); + + p = line_buffer; + + in_size = strlen(line_buffer); + out_size = (pv->current_entry.text+1024) - q; + + retval = iconv( pv->iconv_context, &p, &in_size, &q, &out_size); + *q = '\0'; + + if( ( retval == -1 ) && ( errno == EINVAL ) ) + { + hb_error( "Invalid shift sequence" ); + } else if ( ( retval == -1 ) && ( errno == EILSEQ ) ) + { + hb_error( "Invalid byte for codeset in input, %d bytes discarded", + in_size); + } else if ( ( retval == -1 ) && ( errno == E2BIG ) ) + { + hb_error( "Not enough space in output buffer"); + } + + break; + } + + case k_state_potential_new_entry: + { + const char endpoint[] = "\0"; + const unsigned long potential_entry_number = strtol(line_buffer, (char**)&endpoint, 10); + hb_buffer_t *buffer = NULL; + /* + * Is this really new next entry begin? + */ + if (potential_entry_number == pv->number_of_entries + 1) { + /* + * We found the next entry - or a really rare error condition + */ + if( *pv->current_entry.text ) + { + long length; + char *p; + uint64_t start_time = ( pv->current_entry.start + + pv->subtitle->config.offset ) * 90; + uint64_t stop_time = ( pv->current_entry.stop + + pv->subtitle->config.offset ) * 90; + + if( !( start_time > pv->start_time && stop_time < pv->stop_time ) ) + { + hb_deep_log( 3, "Discarding SRT at time start %lld, stop %lld", start_time, stop_time); + memset( &pv->current_entry, 0, sizeof( srt_entry_t ) ); + ++(pv->number_of_entries); + pv->current_state = k_state_timecode; + continue; + } + + length = strlen( pv->current_entry.text ); + + for( p = pv->current_entry.text; *p; p++) + { + if( *p == '\n' || *p == '\r' ) + { + *p = ' '; + } + } + + buffer = hb_buffer_init( length + 1 ); + + if( buffer ) + { + buffer->start = start_time - pv->start_time; + buffer->stop = stop_time - pv->start_time; + + memcpy( buffer->data, pv->current_entry.text, length + 1 ); + } + } + memset( &pv->current_entry, 0, sizeof( srt_entry_t ) ); + ++(pv->number_of_entries); + pv->current_state = k_state_timecode; + if( buffer ) + { + return buffer; + } + continue; + } else { + /* + * Well.. looks like we are in the wrong mode.. lets add the + * newline we misinterpreted... + */ + strncat(pv->current_entry.text, " ", 1024); + pv->current_state = k_state_inEntry; + } + + break; + } + } + } + + return NULL; +} + +static int decsrtInit( hb_work_object_t * w, hb_job_t * job ) +{ + int retval = 1; + hb_work_private_t * pv; + hb_buffer_t *buffer; + int i; + hb_chapter_t * chapter; + hb_title_t *title = job->title; + + pv = calloc( 1, sizeof( hb_work_private_t ) ); + if( pv ) + { + w->private_data = pv; + + pv->job = job; + + buffer = hb_buffer_init( 0 ); + hb_fifo_push( w->fifo_in, buffer); + + pv->file = fopen( w->subtitle->config.src_filename, "r" ); + + pv->current_state = k_state_potential_new_entry; + pv->number_of_entries = 0; + pv->current_time = 0; + pv->subtitle = w->subtitle; + + /* + * Figure out the start and stop times from teh chapters being + * encoded - drop subtitle not in this range. + */ + pv->start_time = 0; + for( i = 1; i < job->chapter_start; ++i ) + { + chapter = hb_list_item( title->list_chapter, i - 1 ); + if( chapter ) + { + pv->start_time += chapter->duration; + } else { + hb_error( "Could not locate chapter %d for SRT start time", i ); + retval = 0; + } + } + chapter = hb_list_item( title->list_chapter, i - 1 ); + + if( chapter ) + { + pv->stop_time = pv->start_time + chapter->duration; + } else { + hb_error( "Could not locate chapter %d for SRT stop time", i ); + retval = 0; + } + + hb_deep_log( 3, "SRT Start time %lld, stop time %lld", pv->start_time, pv->stop_time); + + pv->iconv_context = iconv_open( "utf8", pv->subtitle->config.src_codeset ); + + + if( pv->iconv_context == (iconv_t) -1 ) + { + hb_error("Could not open the iconv library with those file formats\n"); + + } else { + memset( &pv->current_entry, 0, sizeof( srt_entry_t ) ); + + pv->file = fopen( w->subtitle->config.src_filename, "r" ); + + if( !pv->file ) + { + hb_error("Could not open the SRT subtitle file '%s'\n", + w->subtitle->config.src_filename); + } else { + retval = 0; + } + } + } + + return retval; +} + +static int decsrtWork( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_work_private_t * pv = w->private_data; + hb_buffer_t * in = *buf_in; + hb_buffer_t * out = NULL; + + out = srt_read( pv ); + + if( out ) + { + /* + * Keep a buffer in our input fifo so that we get run. + */ + hb_fifo_push( w->fifo_in, in); + *buf_in = NULL; + *buf_out = out; + } else { + printf("\nSRT Done\n"); + *buf_out = NULL; + return HB_WORK_OK; + } + + return HB_WORK_OK; +} + +static void decsrtClose( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + fclose( pv->file ); + iconv_close(pv->iconv_context); + free( w->private_data ); +} + +hb_work_object_t hb_decsrtsub = +{ + WORK_DECSRTSUB, + "SRT Subtitle Decoder", + decsrtInit, + decsrtWork, + decsrtClose +}; |