OSDN Git Service

CLI: Missed file from SubRip - a symptom of too many views and patches
authoreddyg <eddyg@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Tue, 23 Jun 2009 19:32:39 +0000 (19:32 +0000)
committereddyg <eddyg@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Tue, 23 Jun 2009 19:32:39 +0000 (19:32 +0000)
git-svn-id: svn://localhost/HandBrake/trunk@2604 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/decsrtsub.c [new file with mode: 0644]

diff --git a/libhb/decsrtsub.c b/libhb/decsrtsub.c
new file mode 100644 (file)
index 0000000..190c2df
--- /dev/null
@@ -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
+};