* 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;
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
// 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
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);
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;
}
*/
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 );
+ }
}
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)
*buffer=0x27;
return 1;
case 0x97: // inverted exclamation mark
- *buffer=0xc1;
+ *buffer=0xc2;
*(buffer+1)=0xa1;
return 2;
case 0x98: // asterisk
{
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;
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)
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);
/*
* 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);
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
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])
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 *) "\n");
+ line = 3;
+ } 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;
}
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])
{
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\"> </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;
}
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:
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
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;
}
void handle_end_of_data (struct s_write *wb)
-{
+{
// We issue a EraseDisplayedMemory here so if there's any captions pending
// they get written to file.
handle_command (0x14, 0x2c, wb); // EDM
{
// 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);
}
}
}
}
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
+};