OSDN Git Service

Allow dvd sources that have no audio
[handbrake-jp/handbrake-jp-git.git] / libhb / deccc608sub.c
index 0451b25..5f1e8a1 100644 (file)
  * ccextractor static configuration variables.
  */
 static int debug_608 = 0;
-static int trim_subs = 0;
+static int trim_subs = 1;
 static int nofontcolor = 0;
 static enum encoding_type encoding = ENC_UTF_8;
 static int cc_channel = 1;
-static enum output_format write_format = OF_TRANSCRIPT;
-static int sentence_cap = 1;
+static enum output_format write_format = OF_SRT;
+static int sentence_cap = 0;
 static int subs_delay = 0;
 static LLONG screens_to_process = -1;
 static int processed_enough = 0;
@@ -24,9 +24,12 @@ static int gui_mode_reports = 0;
 static int norollup = 1;
 static int direct_rollup = 0;
 
-static LLONG get_fts(void)
+/*
+ * Get the time of the last buffer that we have received.
+ */
+static LLONG get_fts(struct s_write *wb)
 {
-    return 0;
+    return wb->last_pts;
 }
 
 #define fatal(N, ...) // N
@@ -39,14 +42,11 @@ int     rowdata[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10};
 // we need to bring it into the swrite struct. Same for "str".
 #define INITIAL_ENC_BUFFER_CAPACITY            2048
 
-unsigned char *enc_buffer=NULL; // Generic general purpose buffer
 unsigned char str[2048]; // Another generic general purpose buffer
-unsigned enc_buffer_used;
-unsigned enc_buffer_capacity;
 
-#define GUARANTEE(length) if (length>enc_buffer_capacity) \
-{enc_buffer_capacity*=2; enc_buffer=(unsigned char*) realloc (enc_buffer, enc_buffer_capacity); \
-    if (enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
+#define GUARANTEE(wb, length) if (length>wb->enc_buffer_capacity)            \
+{wb->enc_buffer_capacity*=2; wb->enc_buffer=(unsigned char*) realloc (wb->enc_buffer, wb->enc_buffer_capacity); \
+    if (wb->enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
 }
 
 const unsigned char pac2_attribs[][3]= // Color, font, ident
@@ -153,17 +153,13 @@ const char *color_text[][2]=
 
 int general_608_init (struct s_write *wb)
 {
-    /*
-     * Not currently used.
-     *
-    if( !enc_buffer )
+    if( !wb->enc_buffer )
     {
-        enc_buffer=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY); 
-        if (enc_buffer==NULL)
+        wb->enc_buffer=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY); 
+        if (wb->enc_buffer==NULL)
             return -1;
-        enc_buffer_capacity=INITIAL_ENC_BUFFER_CAPACITY;
+        wb->enc_buffer_capacity=INITIAL_ENC_BUFFER_CAPACITY;
     }
-    */
 
     if( !wb->subline) {
         wb->subline = malloc(2048);
@@ -177,6 +173,10 @@ int general_608_init (struct s_write *wb)
     wb->new_sentence = 1;
     wb->new_channel = 1;
     wb->in_xds_mode = 0;
+
+    wb->hb_buffer = NULL;
+    wb->hb_last_buffer = NULL;
+    wb->last_pts = 0;
     return 0;
 }
 
@@ -187,14 +187,18 @@ int general_608_init (struct s_write *wb)
  */
 void general_608_close (struct s_write *wb)
 {
-    if( enc_buffer ) {
-        free(enc_buffer);
-        enc_buffer_capacity = 0;
-        enc_buffer_used = 0;
+    if( wb->enc_buffer ) {
+        free(wb->enc_buffer);
+        wb->enc_buffer_capacity = 0;
+        wb->enc_buffer_used = 0;
     }
     if( wb->subline ) {
         free(wb->subline);
     }
+
+    if( wb->hb_buffer ) {
+        hb_buffer_close( &wb->hb_buffer );
+    }
 }
 
 
@@ -531,6 +535,8 @@ void get_char_in_unicode (unsigned char *buffer, unsigned char c)
 
 int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number of bytes used
 {
+    if (c==0x00)
+        return 0;
     if (c<0x80) // Regular line-21 character set, mostly ASCII except these exceptions
     {
         switch (c)
@@ -675,7 +681,7 @@ int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number
             *buffer=0x27;                      
             return 1;
         case 0x97: // inverted exclamation mark
-            *buffer=0xc1;
+            *buffer=0xc2;
             *(buffer+1)=0xa1;
             return 2;
         case 0x98: // asterisk
@@ -1431,9 +1437,9 @@ void write_subtitle_file_footer (struct s_write *wb)
             {
                 hb_log ("\r%s\n", str);
             }
-            enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
+            wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
             //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
-            XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+            XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
             break;
         default: // Nothing to do. Only SAMI has a footer
             break;
@@ -1442,9 +1448,9 @@ void write_subtitle_file_footer (struct s_write *wb)
 
 void fhb_log_encoded (FILE *fh, const char *string)
 {
-    GUARANTEE(strlen (string)*3);
-    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) string);
-    fwrite (enc_buffer,enc_buffer_used,1,fh);
+    //GUARANTEE(wb, strlen (string)*3);
+    //wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) string);
+    //fwrite (wb->enc_buffer,wb->enc_buffer_used,1,fh);
 }
 
 void write_subtitle_file_header (struct s_write *wb)
@@ -1455,10 +1461,10 @@ void write_subtitle_file_header (struct s_write *wb)
             break; 
         case OF_SAMI: // This header brought to you by McPoodle's CCASDI  
             //fhb_log_encoded (wb->fh, sami_header);
-            GUARANTEE(strlen (sami_header)*3);
-            enc_buffer_used=encode_line (enc_buffer,(unsigned char *) sami_header);
+            GUARANTEE(wb, strlen (sami_header)*3);
+            wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) sami_header);
             //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
-            XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+            XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
             break;
         case OF_RCWT: // Write header
             //fwrite (rcwt_header, sizeof(rcwt_header),1,wb->fh);
@@ -1490,13 +1496,18 @@ void write_cc_line_as_transcript (struct eia608_screen *data, struct s_write *wb
         /*
          * Put this subtitle in a hb_buffer_t and shove it into the subtitle fifo
          */
-        buffer = hb_buffer_init( strlen( wb->subline ) + 1 );
-        buffer->start = wb->last_pts;
-        buffer->stop = wb->last_pts+1;
-        strcpy( buffer->data, wb->subline );
+        buffer = hb_buffer_init( length + 1 );
+        buffer->start = wb->data608->current_visible_start_ms;
+        buffer->stop = get_fts(wb);
+        memcpy( buffer->data, wb->subline, length + 1 );
         //hb_log("CC %lld: %s", buffer->stop, wb->subline);
 
-        hb_fifo_push( wb->subtitle->fifo_raw, buffer );
+        if (wb->hb_last_buffer) {
+            wb->hb_last_buffer->next = buffer;
+        } else {
+            wb->hb_buffer = buffer;
+        }
+        wb->hb_last_buffer = buffer;
 
         XMLRPC_APPEND(wb->subline,length);
         //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
@@ -1548,7 +1559,7 @@ void write_cc_buffer_to_gui (struct eia608_screen *data, struct s_write *wb)
             hb_log ("###SUBTITLE#");            
             if (!time_reported)
             {
-                LLONG ms_end = get_fts()+subs_delay;           
+                LLONG ms_end = get_fts(wb)+subs_delay;         
                 mstotime (ms_start,&h1,&m1,&s1,&ms1);
                 mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
                 // Note, only MM:SS here as we need to save space in the preview window
@@ -1581,25 +1592,32 @@ int write_cc_buffer_as_srt (struct eia608_screen *data, struct s_write *wb)
     if (ms_start<0) // Drop screens that because of subs_delay start too early
         return 0;
 
-    LLONG ms_end = get_fts()+subs_delay;               
+    LLONG ms_end = get_fts(wb)+subs_delay;             
     mstotime (ms_start,&h1,&m1,&s1,&ms1);
     mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
     char timeline[128];   
     wb->data608->srt_counter++;
     sprintf (timeline,"%u\r\n",wb->data608->srt_counter);
-    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
-    fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
-    XMLRPC_APPEND(enc_buffer,enc_buffer_used);
-    sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
-        h1,m1,s1,ms1, h2,m2,s2,ms2);
-    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
+    //wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) timeline);
+    //fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
+    XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
+    //sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
+    //      h1,m1,s1,ms1, h2,m2,s2,ms2);
+    //wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) timeline);
     if (debug_608)
     {
         hb_log ("\n- - - SRT caption - - -\n");
         hb_log (timeline);
     }
-    fwrite (enc_buffer,enc_buffer_used,1,wb->fh);              
-    XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+    //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);            
+    XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
+    
+    /*
+     * Write all the lines into enc_buffer, and then write that out at the end
+     * ensure that we only have two lines, insert a newline after the first one,
+     * and have a big bottom line (strip spaces from any joined lines).
+     */
+    int line = 1;
     for (i=0;i<15;i++)
     {
         if (data->row_used[i])
@@ -1609,26 +1627,46 @@ int write_cc_buffer_as_srt (struct eia608_screen *data, struct s_write *wb)
                 capitalize(i,data, &wb->new_sentence);
                 correct_case(i,data);
             }
-            int length = get_decoder_line_encoded (wb->subline, i, data);
-            if (debug_608 && encoding!=ENC_UNICODE)
-            {
-                hb_log ("\r");
-                hb_log ("%s\n",wb->subline);
+            /*
+             * The intention was to use a newline but QT doesn't like it, old code still
+             * here just in case..
+             */
+            if (line == 1) {
+                wb->enc_buffer_used = get_decoder_line_encoded (wb->enc_buffer, i, data);
+                line = 2;
+            } else {
+                if (line == 2) {
+                    wb->enc_buffer_used += encode_line (wb->enc_buffer+wb->enc_buffer_used,
+                                                        (unsigned char *) " ");
+                } else {
+                    wb->enc_buffer_used += encode_line (wb->enc_buffer+wb->enc_buffer_used,
+                                                        (unsigned char *) " "); 
+                }
+                wb->enc_buffer_used += get_decoder_line_encoded (wb->enc_buffer+wb->enc_buffer_used, i, data);
             }
-            fwrite (wb->subline, 1, length, wb->fh);
-            XMLRPC_APPEND(wb->subline,length);
-            fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
-            XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
-            wrote_something=1;
-            // fhb_log (wb->fh,encoded_crlf);
         }
     }
+    if (wb->enc_buffer_used)
+    {
+        hb_buffer_t *buffer = hb_buffer_init( wb->enc_buffer_used + 1 );
+        buffer->start = ms_start;
+        buffer->stop = ms_end;
+        memcpy( buffer->data, wb->enc_buffer, wb->enc_buffer_used + 1 );
+        if (wb->hb_last_buffer) {
+            wb->hb_last_buffer->next = buffer;
+        } else {
+            wb->hb_buffer = buffer;
+        }
+        wb->hb_last_buffer = buffer;
+        
+        wrote_something=1;
+    }
     if (debug_608)
     {
         hb_log ("- - - - - - - - - - - -\r\n");
     }
     // fhb_log (wb->fh, encoded_crlf);
-    fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
+    //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
     XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
     return wrote_something;
 }
@@ -1643,16 +1681,16 @@ int write_cc_buffer_as_sami (struct eia608_screen *data, struct s_write *wb)
     if (startms<0) // Drop screens that because of subs_delay start too early
         return 0; 
 
-    LLONG endms   = get_fts()+subs_delay;
+    LLONG endms   = get_fts(wb)+subs_delay;
     endms--; // To prevent overlapping with next line.
     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">\r\n",startms);
     if (debug_608 && encoding!=ENC_UNICODE)
     {
         hb_log ("\r%s\n", str);
     }
-    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
-    fwrite (enc_buffer,enc_buffer_used,1,wb->fh);              
-    XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+    wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
+    fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);              
+    XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
     for (i=0;i<15;i++)
     {
         if (data->row_used[i])
@@ -1680,17 +1718,17 @@ int write_cc_buffer_as_sami (struct eia608_screen *data, struct s_write *wb)
     {
         hb_log ("\r%s\n", str);
     }
-    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
-    fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
-    XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+    wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
+    fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
+    XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
     sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",endms);
     if (debug_608 && encoding!=ENC_UNICODE)
     {
         hb_log ("\r%s\n", str);
     }
-    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
-    fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
-    XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+    wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) str);
+    fwrite (wb->enc_buffer,wb->enc_buffer_used,1,wb->fh);
+    XMLRPC_APPEND(wb->enc_buffer,wb->enc_buffer_used);
     return wrote_something;
 }
 
@@ -2000,7 +2038,7 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct
                     wb->data608->screenfuls_counter++;
             }
             roll_up(wb);               
-            wb->data608->current_visible_start_ms=get_fts();
+            wb->data608->current_visible_start_ms=get_fts(wb);
             wb->data608->cursor_column=0;
             break;
         case COM_ERASENONDISPLAYEDMEMORY:
@@ -2024,7 +2062,7 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct
                     wb->data608->screenfuls_counter++;
             }
             erase_memory (wb,1);
-            wb->data608->current_visible_start_ms=get_fts();
+            wb->data608->current_visible_start_ms=get_fts(wb);
             break;
         case COM_ENDOFCAPTION: // Switch buffers
             // The currently *visible* buffer is leaving, so now we know it's ending
@@ -2032,7 +2070,7 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct
             if (write_cc_buffer (wb))
                 wb->data608->screenfuls_counter++;
             wb->data608->visible_buffer = (wb->data608->visible_buffer==1) ? 2 : 1;
-            wb->data608->current_visible_start_ms=get_fts();
+            wb->data608->current_visible_start_ms=get_fts(wb);
             wb->data608->cursor_column=0;
             wb->data608->cursor_row=0;
             wb->data608->color=default_color;
@@ -2049,17 +2087,9 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct
 
 void handle_end_of_data (struct s_write *wb)
 { 
-    hb_buffer_t *buffer;
-
     // We issue a EraseDisplayedMemory here so if there's any captions pending
     // they get written to file. 
     handle_command (0x14, 0x2c, wb); // EDM
-
-    /*
-     * At the end of the subtitle stream HB wants an empty buffer
-     */
-    buffer = hb_buffer_init( 0 );
-    hb_fifo_push( wb->subtitle->fifo_raw, buffer );
 }
 
 void handle_double (const unsigned char c1, const unsigned char c2, struct s_write *wb)
@@ -2369,7 +2399,7 @@ void process608 (const unsigned char *data, int length, struct s_write *wb)
             {
                 // We don't increase screenfuls_counter here.
                 write_cc_buffer (wb);
-                wb->data608->current_visible_start_ms=get_fts();
+                wb->data608->current_visible_start_ms=get_fts(wb);
             }
         }
     }
@@ -2409,3 +2439,98 @@ unsigned char *debug_608toASC (unsigned char *cc_data, int channel)
     }
     return output;
 }
+
+
+struct hb_work_private_s
+{
+    hb_job_t           * job;
+    struct s_write     * cc608;
+};
+
+int decccInit( hb_work_object_t * w, hb_job_t * job )
+{
+    int retval = 1;
+    hb_work_private_t * pv;
+
+    pv = calloc( 1, sizeof( hb_work_private_t ) );
+    if( pv )
+    {
+        w->private_data = pv;
+
+        pv->job = job;
+
+        pv->cc608 = calloc(1, sizeof(struct s_write));
+
+        if( pv->cc608 )
+        {
+            retval = general_608_init(pv->cc608);
+            if( !retval )
+            {
+                pv->cc608->data608 = calloc(1, sizeof(struct eia608));
+                if( !pv->cc608->data608 )
+                {
+                    retval = 1;
+                }
+            }
+        }
+    }
+    return retval;
+}
+
+int decccWork( 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;
+
+    if ( in->size <= 0 )
+    {
+        /* EOF on input stream - send it downstream & say that we're done */
+        handle_end_of_data(pv->cc608);
+        /*
+         * Grab any pending buffer and output them with the EOF on the end
+         */
+        if (pv->cc608->hb_last_buffer) {
+            pv->cc608->hb_last_buffer->next = in;
+            *buf_out = pv->cc608->hb_buffer;
+            *buf_in = NULL;
+            pv->cc608->hb_buffer = NULL;
+            pv->cc608->hb_last_buffer = NULL;
+        } else {
+            *buf_out = in;
+            *buf_in = NULL;
+        }
+        return HB_WORK_DONE;
+    }
+
+    pv->cc608->last_pts = in->start;
+
+    process608(in->data, in->size, pv->cc608);
+
+    /*
+     * If there is one waiting then pass it on
+     */
+    *buf_out = pv->cc608->hb_buffer;
+    pv->cc608->hb_buffer = NULL;
+    pv->cc608->hb_last_buffer = NULL;
+
+    return HB_WORK_OK; 
+}
+
+void decccClose( hb_work_object_t * w )
+{
+    hb_work_private_t * pv = w->private_data;
+    general_608_close( pv->cc608 );
+    free( pv->cc608->data608 );
+    free( pv->cc608 );
+    free( w->private_data );
+}
+
+hb_work_object_t hb_deccc608 =
+{
+    WORK_DECCC608,
+    "Closed Caption (608) decoder",
+    decccInit,
+    decccWork,
+    decccClose
+};