]> granicus.if.org Git - handbrake/commitdiff
True SSA passthru for MKV.
authorjstebbins <jstebbins.hb@gmail.com>
Thu, 31 Mar 2011 00:05:23 +0000 (00:05 +0000)
committerjstebbins <jstebbins.hb@gmail.com>
Thu, 31 Mar 2011 00:05:23 +0000 (00:05 +0000)
We were converting SSA to UTF8 subs which looses a lot of formatting.
Now we pass through the ssa unmodified and add all fonts as attachments
to the mkv.

git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3891 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/decssasub.c
libhb/muxmkv.c

index ebdc6d25c93b3d05b7b179dbff393c10768520b0..03fb495dbfeeea6454f152656a493cae4213dea3 100644 (file)
@@ -33,6 +33,8 @@ struct hb_work_private_s
     ASS_Renderer *renderer;
     ASS_Track *ssaTrack;
     int readOrder;
+
+    hb_job_t *job;
 };
 
 typedef enum {
@@ -339,6 +341,81 @@ fail:
     return NULL;
 }
 
+static hb_buffer_t * ssa_to_mkv_ssa( hb_work_object_t * w,  hb_buffer_t * in )
+{
+    hb_work_private_t * pv = w->private_data;
+    hb_buffer_t * out_last = NULL;
+    hb_buffer_t * out_first = NULL;
+
+    hb_buffer_realloc( in, in->size + 1 );
+    in->data[in->size] = '\0';
+
+    const char *EOL = "\r\n";
+    char *curLine, *curLine_parserData;
+    for ( curLine = strtok_r( (char *) in->data, EOL, &curLine_parserData );
+          curLine;
+          curLine = strtok_r( NULL, EOL, &curLine_parserData ) )
+    {
+        // Skip empty lines and spaces between adjacent CR and LF
+        if (curLine[0] == '\0')
+            continue;
+        
+        int64_t in_start, in_stop;
+        if ( parse_timing_from_ssa_packet( curLine, &in_start, &in_stop ) )
+            continue;
+
+        int len = strlen(curLine);
+
+        // Convert the SSA line to MKV-SSA format
+        char *layerField = malloc( len );
+        int numPartsRead = sscanf( curLine, "Dialogue: %128[^,],", layerField );
+        if ( numPartsRead != 1 )
+        {
+            free( layerField );
+            continue;
+        }
+        
+        char *styleToTextFields = (char *)find_field( (uint8_t*)curLine, (uint8_t*)curLine + len, 4 );
+        if ( styleToTextFields == NULL ) 
+        {
+            free( layerField );
+            continue;
+        }
+        
+        // The output should always be shorter than the input
+        hb_buffer_t * out = hb_buffer_init( len );
+        char *mkvOut = (char*)out->data;
+        out->start = in_start;
+        out->stop = in_stop;
+
+        sprintf( mkvOut, "%d,%s,%s", 
+                 pv->readOrder++, layerField, styleToTextFields );
+        
+        free( layerField );
+
+        len = strlen(mkvOut);
+        if ( len == 0 )
+        {
+            hb_buffer_close(&out);
+        }
+        else
+        {
+            out->size = len;
+            if ( out_last == NULL )
+            {
+                out_last = out_first = out;
+            }
+            else
+            {
+                out_last->next = out;
+                out_last = out;
+            }
+        }
+    }
+
+    return out_first;
+}
+
 /*
  * SSA line format:
  *   Dialogue: Marked,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text '\0'
@@ -515,6 +592,7 @@ static int decssaInit( hb_work_object_t * w, hb_job_t * job )
 
     pv              = calloc( 1, sizeof( hb_work_private_t ) );
     w->private_data = pv;
+    pv->job = job;
     
     if ( w->subtitle->config.dest == RENDERSUB ) {
         pv->ssa = ass_library_init();
@@ -589,24 +667,29 @@ static int decssaInit( hb_work_object_t * w, hb_job_t * job )
 static int decssaWork( 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_list = NULL;
     
 #if SSA_VERBOSE_PACKETS
     printf("\nPACKET(%"PRId64",%"PRId64"): %.*s\n", in->start/90, in->stop/90, in->size, in->data);
 #endif
     
-    if ( in->size > 0 ) {
-        out_list = ssa_decode_packet(w, in);
-    } else {
-        out_list = hb_buffer_init( 0 );
+    if ( in->size <= 0 )
+    {
+        *buf_out = in;
+        *buf_in = NULL;
+        return HB_WORK_DONE;
     }
-    
-    // Dispose the input packet, as it is no longer needed
-    hb_buffer_close(&in);
-    
-    *buf_in = NULL;
-    *buf_out = out_list;
+
+    if ( w->subtitle->config.dest == PASSTHRUSUB && pv->job->mux == HB_MUX_MKV )
+    {
+        *buf_out = ssa_to_mkv_ssa(w, in);
+    }
+    else
+    {
+        *buf_out = ssa_decode_packet(w, in);
+    }
+
     return HB_WORK_OK;
 }
 
index 287f677fa19706f4851a086977c614bc102ec3cc..aed5940b40079636ab2e42d1a1cc8aa040f6ce4f 100644 (file)
@@ -48,6 +48,7 @@ static int MKVInit( hb_mux_object_t * m )
 
     uint8_t         *avcC = NULL;
     uint8_t         default_track_flag = 1;
+    uint8_t         need_fonts = 0;
     int             avcC_len, i, j;
     ogg_packet      *ogg_headers[3];
     mk_TrackConfig *track;
@@ -309,7 +310,15 @@ static int MKVInit( hb_mux_object_t * m )
                 track->codecPrivateSize = len + 1;
                 break;
             case TEXTSUB:
-                track->codecID = MK_SUBTITLE_UTF8;
+                if (subtitle->source == SSASUB)
+                {
+                    track->codecID = MK_SUBTITLE_SSA;
+                    need_fonts = 1;
+                    track->codecPrivate = subtitle->extradata;
+                    track->codecPrivateSize = subtitle->extradata_size;
+                }
+                else
+                    track->codecID = MK_SUBTITLE_UTF8;
                 break;
             default:
                 continue;
@@ -331,6 +340,27 @@ static int MKVInit( hb_mux_object_t * m )
         mux_data->track = mk_createTrack(m->file, track);
     }
 
+    if (need_fonts)
+    {
+        hb_list_t * list_attachment = job->title->list_attachment;
+        int i;
+        for ( i = 0; i < hb_list_count(list_attachment); i++ )
+        {
+            hb_attachment_t * attachment = hb_list_item( list_attachment, i );
+
+            if ( attachment->type == FONT_TTF_ATTACH )
+            {
+                mk_createAttachment(
+                    m->file,
+                    attachment->name,
+                    NULL,
+                    "application/x-truetype-font",
+                    attachment->data,
+                    attachment->size);
+            }
+        }
+    }
+
     if( mk_writeHeader( m->file, "HandBrake " HB_PROJECT_VERSION) < 0 )
     {
         hb_error( "Failed to write to output file, disk full?");