/* * Decodes a single SSA packet to one or more TEXTSUB or PICTURESUB subtitle packets. * * SSA packet format: * ( Dialogue: Marked,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text CR LF ) + * 1 2 3 4 5 6 7 8 9 10 */ static hb_buffer_t *ssa_decode_packet( hb_work_object_t * w, hb_buffer_t *in ) { // Store NULL after the end of the buffer to make using string processing safe hb_buffer_realloc(in, ++in->size); in->data[in->size - 1] = '\0'; hb_buffer_list_t list; hb_buffer_t *buf; hb_buffer_list_clear(&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 buf = ssa_decode_line_to_mkv_ssa(w, in, (uint8_t *)curLine, strlen(curLine)); hb_buffer_list_append(&list, buf); } return hb_buffer_list_clear(&list); }
static int decssaWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { hb_buffer_t * in = *buf_in; #if SSA_VERBOSE_PACKETS printf("\nPACKET(%"PRId64",%"PRId64"): %.*s\n", in->s.start/90, in->s.stop/90, in->size, in->data); #endif *buf_in = NULL; *buf_out = in; if (in->s.flags & HB_BUF_FLAG_EOF) { return HB_WORK_DONE; } // Not much to do here. ffmpeg already supplies SSA subtitles in the // requried matroska packet format. // // We require string termination of the buffer hb_buffer_realloc(in, ++in->size); in->data[in->size - 1] = '\0'; return HB_WORK_OK; }
static hb_buffer_t * ssa_to_mkv_ssa( hb_work_object_t * w, hb_buffer_t * in ) { hb_buffer_t * out_last = NULL; hb_buffer_t * out_first = NULL; // Store NULL after the end of the buffer to make using string processing safe hb_buffer_realloc(in, ++in->size); in->data[in->size - 1] = '\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 ) ) { hb_buffer_t * out; out = ssa_decode_line_to_mkv_ssa( w, (uint8_t *) curLine, strlen( curLine ), in->sequence ); if( out ) { if ( out_last == NULL ) { out_last = out_first = out; } else { out_last->next = out; out_last = out; } } } return out_first; }
static void IndexAddInt32( hb_buffer_t * b, uint32_t val ) { if( b->size + 16 > b->alloc ) { hb_log( "muxavi: reallocing index (%d MB)", 1 + b->alloc / 1024 / 1024 ); hb_buffer_realloc( b, b->alloc + 1024 * 1024 ); } b->data[b->size++] = val & 0xFF; b->data[b->size++] = ( val >> 8 ) & 0xFF; b->data[b->size++] = ( val >> 16 ) & 0xFF; b->data[b->size++] = val >> 24; }
static int dectx3gWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { hb_buffer_t * in = *buf_in; hb_buffer_t * out = NULL; // Warn if the subtitle's duration has not been passed through by the demuxer, // which will prevent the subtitle from displaying at all if ( in->s.stop == 0 ) { hb_log( "dectx3gsub: subtitle packet lacks duration" ); } if ( in->size > 0 ) { out = tx3g_decode_to_utf8(in); } else { out = hb_buffer_init( 0 ); } if ( out != NULL ) { // 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') { hb_buffer_realloc(out, ++out->size); out->data[out->size - 1] = '\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); } } // Dispose the input packet, as it is no longer needed hb_buffer_close(&in); *buf_in = NULL; *buf_out = out; return HB_WORK_OK; }
void hb_srt_to_ssa(hb_buffer_t *sub_in, int line) { if (sub_in->size == 0) return; // null terminate input if not already terminated if (sub_in->data[sub_in->size-1] != 0) { hb_buffer_realloc(sub_in, ++sub_in->size); sub_in->data[sub_in->size - 1] = 0; } char * srt = (char*)sub_in->data; // SSA markup expands a little over SRT, so allocate a bit of extra // space. More will be realloc'd if needed. hb_buffer_t * sub = hb_buffer_init(sub_in->size + 80); char * ssa, *ssa_markup; int skip, len, pos, ii; // Exchange data between input sub and new ssa_sub // After this, sub_in contains ssa data hb_buffer_swap_copy(sub_in, sub); ssa = (char*)sub_in->data; sprintf((char*)sub_in->data, "%d,,Default,,0,0,0,,", line); pos = strlen((char*)sub_in->data); ii = 0; while (srt[ii] != '\0') { if ((ssa_markup = srt_markup_to_ssa(srt + ii, &skip)) != NULL) { len = strlen(ssa_markup); hb_buffer_realloc(sub_in, pos + len + 1); // After realloc, sub_in->data may change ssa = (char*)sub_in->data; sprintf(ssa + pos, "%s", ssa_markup); free(ssa_markup); pos += len; ii += skip; } else { hb_buffer_realloc(sub_in, pos + 4); // After realloc, sub_in->data may change ssa = (char*)sub_in->data; if (srt[ii] == '\r') { ssa[pos++] = '\\'; ssa[pos++] = 'N'; ii++; if (srt[ii] == '\n') { ii++; } } else if (srt[ii] == '\n') { ssa[pos++] = '\\'; ssa[pos++] = 'N'; ii++; } else { ssa[pos++] = srt[ii++]; } } } ssa[pos] = '\0'; sub_in->size = pos + 1; hb_buffer_close(&sub); }
/* * Decodes a single SSA packet to one or more TEXTSUB or PICTURESUB subtitle packets. * * SSA packet format: * ( Dialogue: Marked,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text CR LF ) + * 1 2 3 4 5 6 7 8 9 10 */ static hb_buffer_t *ssa_decode_packet( hb_work_object_t * w, hb_buffer_t *in ) { // Store NULL after the end of the buffer to make using string processing safe hb_buffer_realloc(in, ++in->size); in->data[in->size - 1] = '\0'; 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; if ( w->subtitle->config.dest == PASSTHRUSUB ) { out = ssa_decode_line_to_utf8( (uint8_t *) curLine, strlen( curLine ), in->sequence ); if ( out == NULL ) continue; // 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') { hb_buffer_realloc(out, ++out->size); out->data[out->size - 1] = '\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; } } else if ( w->subtitle->config.dest == RENDERSUB ) { out = ssa_decode_line_to_mkv_ssa( w, (uint8_t *) curLine, strlen( curLine ), in->sequence ); if ( out == NULL ) continue; } // Append 'out' to 'out_list' *nextPtr = out; nextPtr = &out->next; } // For point-to-point encoding, when the start time of the stream // may be offset, the timestamps of the subtitles must be offset as well. // // HACK: Here we are making the assumption that, under normal circumstances, // the output display time of the first output packet is equal to the // display time of the input packet. // // During point-to-point encoding, the display time of the input // packet will be offset to compensate. // // Therefore we offset all of the output packets by a slip amount // such that first output packet's display time aligns with the // input packet's display time. This should give the correct time // when point-to-point encoding is in effect. if (out_list && out_list->s.start > in->s.start) { int64_t slip = out_list->s.start - in->s.start; hb_buffer_t *out; out = out_list; while (out) { out->s.start -= slip; out->s.stop -= slip; out = out->next; } } return out_list; }