+ hb_buffer_t *out_list = NULL;
+ hb_buffer_t **nextPtr = &out_list;
+
+ 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;
+
+ // Decode an individual SSA line
+ hb_buffer_t *out = ssa_decode_to_utf8_line( (uint8_t*)curLine, strlen( curLine ) );
+
+ // We shouldn't be storing the extra NULL character,
+ // but the MP4 muxer expects this, unfortunately.
+ if ( out->size > 0 && out->data[out->size - 1] != '\0' ) {
+ // NOTE: out->size remains unchanged
+ hb_buffer_realloc( out, out->size + 1 );
+ out->data[out->size] = '\0';
+ }
+
+ // If the input packet was non-empty, do not pass through
+ // an empty output packet (even if the subtitle was empty),
+ // as this would be interpreted as an end-of-stream
+ if ( in->size > 0 && out->size == 0 ) {
+ hb_buffer_close(&out);
+ continue;
+ }
+
+ // Append 'out' to 'out_list'
+ *nextPtr = out;
+ nextPtr = &out->next;
+ }
+
+ return out_list;
+}
+
+/*
+ * SSA line format:
+ * Dialogue: Marked,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text '\0'
+ * 1 2 3 4 5 6 7 8 9 10
+ */
+static hb_buffer_t *ssa_decode_to_utf8_line( uint8_t *in_data, int in_size )
+{
+ uint8_t *pos = in_data;
+ uint8_t *end = in_data + in_size;
+