Exemple #1
0
int write_cc_bitmap_as_srt(struct cc_subtitle *sub, struct encoder_ctx *context)
{
	int ret = 0;
#ifdef ENABLE_OCR
	struct cc_bitmap* rect;
	LLONG ms_start, ms_end;
	unsigned h1,m1,s1,ms1;
	unsigned h2,m2,s2,ms2;
	char timeline[128];
	int len = 0;
	int used;

	if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
	{
		ms_start = context->prev_start;
		ms_end = sub->start_time;
	}
	else if ( !(sub->flags & SUB_EOD_MARKER))
	{
		ms_start = sub->start_time;
		ms_end = sub->end_time;
	}
	else if (context->prev_start == -1 && (sub->flags & SUB_EOD_MARKER))
	{
		ms_start = 1;
		ms_end = sub->start_time;
	}

	if(sub->nb_data == 0 )
		return 0;

	if(sub->flags & SUB_EOD_MARKER)
		context->prev_start =  sub->start_time;

	rect = sub->data;
	if (rect[0].ocr_text && *(rect[0].ocr_text))
	{
		if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
		{
			mstotime (ms_start,&h1,&m1,&s1,&ms1);
			mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
			context->srt_counter++;
			sprintf(timeline, "%u\r\n", context->srt_counter);
			used = encode_line(context, context->buffer,(unsigned char *) timeline);
			write(context->out->fh, context->buffer, used);
			sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
				h1,m1,s1,ms1, h2,m2,s2,ms2);
			used = encode_line(context, context->buffer,(unsigned char *) timeline);
			write (context->out->fh, context->buffer, used);
			len = strlen(rect[0].ocr_text);
			write (context->out->fh, rect[0].ocr_text, len);
			write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
		}
	}
#endif
	sub->nb_data = 0;
	freep(&sub->data);
	return ret;

}
int write_cc_buffer_as_smptett (struct eia608_screen *data, struct s_write *wb)
{
    unsigned h1,m1,s1,ms1;
    unsigned h2,m2,s2,ms2;
    int wrote_something=0;
    LLONG startms = wb->data608->current_visible_start_ms;

    startms+=subs_delay;
    if (startms<0) // Drop screens that because of subs_delay start too early
        return 0; 

    LLONG endms   = get_visible_end()+subs_delay;
    endms--; // To prevent overlapping with next line.
    mstotime (startms,&h1,&m1,&s1,&ms1);
    mstotime (endms-1,&h2,&m2,&s2,&ms2);

    sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u,%03u\">\n",h1,m1,s1,ms1, h2,m2,s2,ms2);

    if (encoding!=ENC_UNICODE)
    {
        dbg_print(DMT_608, "\r%s\n", str);
    }
    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
    write (wb->fh, enc_buffer,enc_buffer_used);
    for (int i=0;i<15;i++)
    {
        if (data->row_used[i])
        {				
            int length = get_decoder_line_encoded (subline, i, data);
            if (encoding!=ENC_UNICODE)
            {
                dbg_print(DMT_608, "\r");
                dbg_print(DMT_608, "%s\n",subline);
            }
            write (wb->fh, subline, length);            
            wrote_something=1;
            //if (i!=14)            
              //write (wb->fh, encoded_br, encoded_br_length);            
            write (wb->fh,encoded_crlf, encoded_crlf_length);
        }
    }
    sprintf ((char *) str,"</p>\n");
    if (encoding!=ENC_UNICODE)
    {
        dbg_print(DMT_608, "\r%s\n", str);
    }
    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
    write (wb->fh, enc_buffer,enc_buffer_used);

    if (encoding!=ENC_UNICODE)
    {
        dbg_print(DMT_608, "\r%s\n", str);
    }
    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
    //write (wb->fh, enc_buffer,enc_buffer_used);

    return wrote_something;
}
void write_cc_buffer_to_gui(struct eia608_screen *data, struct encoder_ctx *context)
{
	unsigned h1, m1, s1, ms1;
	unsigned h2, m2, s2, ms2;
	LLONG ms_start;
	int with_data = 0;

	for (int i = 0; i<15; i++)
	{
		if (data->row_used[i])
			with_data = 1;
	}
	if (!with_data)
		return;

	ms_start = data->start_time;

	ms_start += context->subs_delay;
	if (ms_start<0) // Drop screens that because of subs_delay start too early
		return;
	int time_reported = 0;
	for (int i = 0; i<15; i++)
	{
		if (data->row_used[i])
		{
			fprintf(stderr, "###SUBTITLE#");
			if (!time_reported)
			{
				LLONG ms_end = data->end_time;
				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
				fprintf(stderr, "%02u:%02u#%02u:%02u#",
					h1 * 60 + m1, s1, h2 * 60 + m2, s2);
				time_reported = 1;
			}
			else
				fprintf(stderr, "##");

			// We don't capitalize here because whatever function that was used
			// before to write to file already took care of it.
			int length = get_decoder_line_encoded_for_gui(context->subline, i, data);
			fwrite(context->subline, 1, length, stderr);
			fwrite("\n", 1, 1, stderr);
		}
	}
	fflush(stderr);
}
int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context)
{
	int ret = 0;
#ifdef ENABLE_OCR
	struct cc_bitmap* rect;

	unsigned h1,m1,s1,ms1;
	unsigned h2,m2,s2,ms2;

	LLONG start_time, end_time;

	if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
	{
		start_time = context->prev_start + context->subs_delay;
		end_time = sub->start_time - 1;
	}
	else if ( !(sub->flags & SUB_EOD_MARKER))
	{
		start_time = sub->start_time + context->subs_delay;
		end_time = sub->end_time - 1;
	}

	if(sub->nb_data == 0 )
		return ret;
	rect = sub->data;

	if ( sub->flags & SUB_EOD_MARKER )
		context->prev_start =  sub->start_time;


	if (rect[0].ocr_text && *(rect[0].ocr_text))
	{
		if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
		{
			char *token = NULL;
			token = strtok(rect[0].ocr_text ,"\r\n");
			while (token)
			{

				if (context->transcript_settings->showStartTime)
				{
					char buf1[80];
					if (context->transcript_settings->relativeTimestamp)
					{
						millis_to_date(start_time + context->subs_delay, buf1, context->date_format, context->millis_separator);
						fdprintf(context->out->fh, "%s|", buf1);
					}
					else
					{
						mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
						time_t start_time_int = (start_time + context->subs_delay) / 1000;
						int start_time_dec = (start_time + context->subs_delay) % 1000;
						struct tm *start_time_struct = gmtime(&start_time_int);
						strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
						fdprintf(context->out->fh, "%s%c%03d|", buf1,context->millis_separator,start_time_dec);
					}
				}

				if (context->transcript_settings->showEndTime)
				{
					char buf2[80];
					if (context->transcript_settings->relativeTimestamp)
					{
						millis_to_date(end_time, buf2, context->date_format, context->millis_separator);
						fdprintf(context->out->fh, "%s|", buf2);
					}
					else
					{
						mstotime(get_fts() + context->subs_delay, &h2, &m2, &s2, &ms2);
						time_t end_time_int = end_time / 1000;
						int end_time_dec = end_time % 1000;
						struct tm *end_time_struct = gmtime(&end_time_int);
						strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
						fdprintf(context->out->fh, "%s%c%03d|", buf2,context->millis_separator,end_time_dec);
					}
				}
				if (context->transcript_settings->showCC)
				{
					fdprintf(context->out->fh,"%s|",language[sub->lang_index]);
				}
				if (context->transcript_settings->showMode)
				{
					fdprintf(context->out->fh,"DVB|");
				}
				fdprintf(context->out->fh,"%s\n",token);
				token = strtok(NULL,"\r\n");

			}

		}
	}
#endif

	sub->nb_data = 0;
	freep(&sub->data);
	return ret;

}
void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx *context, int line_number)
{
	int ret = 0;
	unsigned int h1,m1,s1,ms1;
	unsigned int h2,m2,s2,ms2;
	LLONG start_time = data->start_time;
	LLONG end_time = data->end_time;
	if (context->sentence_cap)
	{
		capitalize (line_number,data);
		correct_case(line_number,data);
	}
	int length = get_decoder_str_basic (context->subline, data->characters[line_number], context->trim_subs, context->encoding);
	if (context->encoding!=CCX_ENC_UNICODE)
	{
		dbg_print(CCX_DMT_DECODER_608, "\r");
		dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
	}
	if (length>0)
	{
		if (data->start_time == -1)
		{
			// CFS: Means that the line has characters but we don't have a timestamp for the first one. Since the timestamp
			// is set for example by the write_char function, it possible that we don't have one in empty lines (unclear)
			// For now, let's not consider this a bug as before and just return.
			// fatal (EXIT_BUG_BUG, "Bug in timedtranscript (ts_start_of_current_line==-1). Please report.");
			return;
		}

		if (context->transcript_settings->showStartTime){
			char buf1[80];
			if (context->transcript_settings->relativeTimestamp){
				millis_to_date(start_time + context->subs_delay, buf1, context->date_format, context->millis_separator);
				fdprintf(context->out->fh, "%s|", buf1);
			}
			else {
				mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
				time_t start_time_int = (start_time + context->subs_delay) / 1000;
				int start_time_dec = (start_time + context->subs_delay) % 1000;
				struct tm *start_time_struct = gmtime(&start_time_int);
				strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
				fdprintf(context->out->fh, "%s%c%03d|", buf1,context->millis_separator,start_time_dec);
			}
		}

		if (context->transcript_settings->showEndTime){
			char buf2[80];
			if (context->transcript_settings->relativeTimestamp){
				millis_to_date(end_time, buf2, context->date_format, context->millis_separator);
				fdprintf(context->out->fh, "%s|", buf2);
			}
			else {
				mstotime(get_fts() + context->subs_delay, &h2, &m2, &s2, &ms2);
				time_t end_time_int = (end_time + context->subs_delay) / 1000;
				int end_time_dec = (end_time + context->subs_delay) % 1000;
				struct tm *end_time_struct = gmtime(&end_time_int);
				strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
				fdprintf(context->out->fh, "%s%c%03d|", buf2,context->millis_separator,end_time_dec);
			}
		}

		if (context->transcript_settings->showCC){
			fdprintf(context->out->fh, "CC%d|", data->my_field == 1 ? data->channel : data->channel + 2); // Data from field 2 is CC3 or 4
		}
		if (context->transcript_settings->showMode){
			const char *mode = "???";
			switch (data->mode)
			{
			case MODE_POPON:
				mode = "POP";
				break;
			case MODE_FAKE_ROLLUP_1:
				mode = "RU1";
				break;
			case MODE_ROLLUP_2:
				mode = "RU2";
				break;
			case MODE_ROLLUP_3:
				mode = "RU3";
				break;
			case MODE_ROLLUP_4:
				mode = "RU4";
				break;
			case MODE_TEXT:
				mode = "TXT";
				break;
			case MODE_PAINTON:
				mode = "PAI";
				break;
			}
			fdprintf(context->out->fh, "%s|", mode);
		}

		ret = write(context->out->fh, context->subline, length);
		if(ret < length)
		{
			mprint("Warning:Loss of data\n");
		}

		ret = write(context->out->fh, encoded_crlf, encoded_crlf_length);
		if(ret <  encoded_crlf_length)
		{
			mprint("Warning:Loss of data\n");
		}
	}
	// fprintf (wb->fh,encoded_crlf);
}
int write_cc_subtitle_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context)
{
	int length;
	int ret = 0;
	unsigned int h1,m1,s1,ms1;
	unsigned int h2,m2,s2,ms2;
	LLONG start_time;
	LLONG end_time;
	char *str;
	struct cc_subtitle *osub = sub;
	struct cc_subtitle *lsub = sub;

	while(sub)
	{
		if(sub->type == CC_TEXT)
		{
			start_time = sub->start_time;
			end_time = sub->end_time;
		}
		if (context->sentence_cap)
		{
			//TODO capitalize (line_number,data);
			//TODO correct_case(line_number,data);
		}

		str = sub->data;
		length = strlen(str);
		if (context->encoding!=CCX_ENC_UNICODE)
		{
			dbg_print(CCX_DMT_DECODER_608, "\r");
			dbg_print(CCX_DMT_DECODER_608, "%s\n", str);
		}

		if (length>0)
		{
			if (start_time == -1)
			{
				// CFS: Means that the line has characters but we don't have a timestamp for the first one. Since the timestamp
				// is set for example by the write_char function, it possible that we don't have one in empty lines (unclear)
				// For now, let's not consider this a bug as before and just return.
				// fatal (EXIT_BUG_BUG, "Bug in timedtranscript (ts_start_of_current_line==-1). Please report.");
				return 0;
			}

			if (context->transcript_settings->showStartTime){
				char buf1[80];
				if (context->transcript_settings->relativeTimestamp){
					millis_to_date(start_time + context->subs_delay, buf1, context->date_format, context->millis_separator);
					fdprintf(context->out->fh, "%s|", buf1);
				}
				else {
					mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
					time_t start_time_int = (start_time + context->subs_delay) / 1000;
					int start_time_dec = (start_time + context->subs_delay) % 1000;
					struct tm *start_time_struct = gmtime(&start_time_int);
					strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
					fdprintf(context->out->fh, "%s%c%03d|", buf1,context->millis_separator,start_time_dec);
				}
			}

			if (context->transcript_settings->showEndTime){
				char buf2[80];
				if (context->transcript_settings->relativeTimestamp){
					millis_to_date(end_time, buf2, context->date_format, context->millis_separator);
					fdprintf(context->out->fh, "%s|", buf2);
				}
				else {
					mstotime(get_fts() + context->subs_delay, &h2, &m2, &s2, &ms2);
					time_t end_time_int = (end_time + context->subs_delay) / 1000;
					int end_time_dec = (end_time + context->subs_delay) % 1000;
					struct tm *end_time_struct = gmtime(&end_time_int);
					strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
					fdprintf(context->out->fh, "%s%c%03d|", buf2,context->millis_separator,end_time_dec);
				}
			}

			if (context->transcript_settings->showCC) {
				if(context->in_fileformat == 2 )
					fdprintf(context->out->fh, sub->info);
				else
					//TODO, data->my_field == 1 ? data->channel : data->channel + 2); // Data from field 2 is CC3 or 4
					fdprintf(context->out->fh, "CC?|");
			}
			if (context->transcript_settings->showMode){
				fdprintf(context->out->fh, "%s|", sub->mode);
			}
			ret = write(context->out->fh, str, length);
			if(ret < length)
			{
				mprint("Warning:Loss of data\n");
			}

			ret = write(context->out->fh, encoded_crlf, encoded_crlf_length);
			if(ret <  encoded_crlf_length)
			{
				mprint("Warning:Loss of data\n");
			}
		}

		freep(&sub->data);
		lsub = sub;
		sub = sub->next;
	}

	while(lsub != osub)
	{
		sub = lsub->prev;
		freep(&lsub);
		lsub = sub;
	}

	return ret;
}
Exemple #7
0
/* The timing here is not PTS based, but output based, i.e. user delay must be accounted for
   if there is any */
int write_stringz_as_srt(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end)
{
	int used;
	unsigned h1,m1,s1,ms1;
	unsigned h2,m2,s2,ms2;
	char timeline[128];

	if(!string || !string[0])
		return 0;

	mstotime (ms_start,&h1,&m1,&s1,&ms1);
	mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
	context->srt_counter++;
	sprintf(timeline, "%u%s", context->srt_counter, context->encoded_crlf);
	used = encode_line(context, context->buffer,(unsigned char *) timeline);
	write(context->out->fh, context->buffer, used);
	sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
		h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
	used = encode_line(context, context->buffer,(unsigned char *) timeline);
	dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption - - -\n");
	dbg_print(CCX_DMT_DECODER_608, "%s",timeline);

	write(context->out->fh, context->buffer, used);
	int len=strlen (string);
	unsigned char *unescaped= (unsigned char *) malloc (len+1);
	unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
	if (el==NULL || unescaped==NULL)
		fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_srt() - not enough memory.\n");
	int pos_r=0;
	int pos_w=0;
	// Scan for \n in the string and replace it with a 0
	while (pos_r<len)
	{
		if (string[pos_r]=='\\' && string[pos_r+1]=='n')
		{
			unescaped[pos_w]=0;
			pos_r+=2;
		}
		else
		{
			unescaped[pos_w]=string[pos_r];
			pos_r++;
		}
		pos_w++;
	}
	unescaped[pos_w]=0;
	// Now read the unescaped string (now several string'z and write them)
	unsigned char *begin=unescaped;
	while (begin<unescaped+len)
	{
		unsigned int u = encode_line (context, el, begin);
		if (context->encoding != CCX_ENC_UNICODE)
		{
			dbg_print(CCX_DMT_DECODER_608, "\r");
			dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
		}
		write(context->out->fh, el, u);
		write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
		begin+= strlen ((const char *) begin)+1;
	}

	dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");

	write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
	free(el);
	free(unescaped);

	return 0;
}
Exemple #8
0
int write_cc_buffer_as_srt(struct eia608_screen *data, struct encoder_ctx *context)
{
	int used;
	unsigned h1,m1,s1,ms1;
	unsigned h2,m2,s2,ms2;
	LLONG ms_start, ms_end;
	int wrote_something = 0;
	ms_start = data->start_time;

	int prev_line_start=-1, prev_line_end=-1; // Column in which the previous line started and ended, for autodash
	int prev_line_center1=-1, prev_line_center2=-1; // Center column of previous line text
	int empty_buf=1;
	for (int i=0;i<15;i++)
	{
		if (data->row_used[i])
		{
			empty_buf=0;
			break;
		}
	}
	if (empty_buf) // Prevent writing empty screens. Not needed in .srt
		return 0;

	ms_start+=context->subs_delay;
	if (ms_start<0) // Drop screens that because of subs_delay start too early
		return 0;

	ms_end = data->end_time;

	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];
	context->srt_counter++;
	sprintf(timeline, "%u%s", context->srt_counter, context->encoded_crlf);
	used = encode_line(context, context->buffer,(unsigned char *) timeline);
	write(context->out->fh, context->buffer, used);
	sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u%s",
		h1, m1, s1, ms1, h2, m2, s2, ms2, context->encoded_crlf);
	used = encode_line(context, context->buffer,(unsigned char *) timeline);

	dbg_print(CCX_DMT_DECODER_608, "\n- - - SRT caption ( %d) - - -\n", context->srt_counter);
	dbg_print(CCX_DMT_DECODER_608, "%s",timeline);

	write (context->out->fh, context->buffer, used);
	for (int i=0;i<15;i++)
	{
		if (data->row_used[i])
		{
			if (context->sentence_cap)
			{
				capitalize (i,data);
				correct_case(i,data);
			}
			if (context->autodash && context->trim_subs)
			{
				int first=0, last=31, center1=-1, center2=-1;
				unsigned char *line = data->characters[i];
				int do_dash=1, colon_pos=-1;
				find_limit_characters(line,&first,&last);
				if (first==-1 || last==-1)  // Probably a bug somewhere though
					break;
				// Is there a speaker named, for example: TOM: What are you doing?
				for (int j=first;j<=last;j++)
				{
					if (line[j]==':')
					{
						colon_pos=j;
						break;
					}
					if (!isupper (line[j]))
						break;
				}
				if (prev_line_start==-1)
					do_dash=0;
				if (first==prev_line_start) // Case of left alignment
					do_dash=0;
				if (last==prev_line_end)  // Right align
					do_dash=0;
				if (first>prev_line_start && last<prev_line_end) // Fully contained
					do_dash=0;
				if ((first>prev_line_start && first<prev_line_end) || // Overlap
						(last>prev_line_start && last<prev_line_end))
					do_dash=0;

				center1=(first+last)/2;
				if (colon_pos!=-1)
				{
					while (colon_pos<CCX_DECODER_608_SCREEN_WIDTH &&
							(line[colon_pos]==':' ||
							 line[colon_pos]==' ' ||
							 line[colon_pos]==0x89))
						colon_pos++; // Find actual text
					center2=(colon_pos+last)/2;
				}
				else
					center2=center1;

				if (center1>=prev_line_center1-1 && center1<=prev_line_center1+1 && center1!=-1) // Center align
					do_dash=0;
				if (center2>=prev_line_center2-2 && center1<=prev_line_center2+2 && center1!=-1) // Center align
					do_dash=0;

				if (do_dash)
					write(context->out->fh, "- ", 2);
				prev_line_start=first;
				prev_line_end=last;
				prev_line_center1=center1;
				prev_line_center2=center2;

			}
			int length = get_decoder_line_encoded (context, context->subline, i, data);
			if (context->encoding!=CCX_ENC_UNICODE)
			{
				dbg_print(CCX_DMT_DECODER_608, "\r");
				dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline);
			}
			write(context->out->fh, context->subline, length);
			write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
			wrote_something=1;
			// fprintf (wb->fh,context->encoded_crlf);
		}
	}
	dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");

	// fprintf (wb->fh, context->encoded_crlf);
	write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
	return wrote_something;
}
Exemple #9
0
int write_cc_buffer_as_srt (struct eia608_screen *data, struct s_write *wb)
{
    unsigned h1,m1,s1,ms1;
    unsigned h2,m2,s2,ms2;
    int wrote_something = 0;
    LLONG ms_start= wb->data608->current_visible_start_ms;

	int empty_buf=1;
    for (int i=0;i<15;i++)
    {
        if (data->row_used[i])
		{
			empty_buf=0;
			break;
		}
	}
	if (empty_buf) // Prevent writing empty screens. Not needed in .srt
		return 0;

    ms_start+=subs_delay;
    if (ms_start<0) // Drop screens that because of subs_delay start too early
        return 0;

	LLONG ms_end = get_visible_end()+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);
    write (wb->fh, 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);

    dbg_print(DMT_608, "\n- - - SRT caption - - -\n");
    dbg_print(DMT_608, "%s",timeline);

    write (wb->fh, enc_buffer,enc_buffer_used);		
    for (int i=0;i<15;i++)
    {
        if (data->row_used[i])
        {		
            if (sentence_cap)
            {
                capitalize (i,data);
                correct_case(i,data);
            }
            int length = get_decoder_line_encoded (subline, i, data);
            if (encoding!=ENC_UNICODE)
            {
                dbg_print(DMT_608, "\r");
                dbg_print(DMT_608, "%s\n",subline);
            }
            write (wb->fh, subline, length);
            write (wb->fh, encoded_crlf, encoded_crlf_length);
            wrote_something=1;
            // fprintf (wb->fh,encoded_crlf);
        }
    }
    dbg_print(DMT_608, "- - - - - - - - - - - -\r\n");
    
    // fprintf (wb->fh, encoded_crlf);
    write (wb->fh, encoded_crlf, encoded_crlf_length);
    return wrote_something;
}
void write_stringz_as_smptett (char *string, struct s_write *wb, LLONG ms_start, LLONG ms_end)
{
    unsigned h1,m1,s1,ms1;
    unsigned h2,m2,s2,ms2;

    mstotime (ms_start,&h1,&m1,&s1,&ms1);
    mstotime (ms_end-1,&h2,&m2,&s2,&ms2);

    sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\" end=\"%02u:%02u:%02u.%03u\">\r\n",h1,m1,s1,ms1, h2,m2,s2,ms2);
    if (encoding!=ENC_UNICODE)
    {
        dbg_print(DMT_608, "\r%s\n", str);
    }
    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
    write (wb->fh, enc_buffer,enc_buffer_used);		
    int len=strlen (string);
    unsigned char *unescaped= (unsigned char *) malloc (len+1); 
    unsigned char *el = (unsigned char *) malloc (len*3+1); // Be generous
    if (el==NULL || unescaped==NULL)
        fatal (EXIT_NOT_ENOUGH_MEMORY, "In write_stringz_as_sami() - not enough memory.\n");
    int pos_r=0;
    int pos_w=0;
    // Scan for \n in the string and replace it with a 0
    while (pos_r<len)
    {
        if (string[pos_r]=='\\' && string[pos_r+1]=='n')
        {
            unescaped[pos_w]=0;
            pos_r+=2;            
        }
        else
        {
            unescaped[pos_w]=string[pos_r];
            pos_r++;
        }
        pos_w++;
    }
    unescaped[pos_w]=0;
    // Now read the unescaped string (now several string'z and write them)    
    unsigned char *begin=unescaped;
    while (begin<unescaped+len)
    {
        unsigned int u = encode_line (el, begin);
        if (encoding!=ENC_UNICODE)
        {
            dbg_print(DMT_608, "\r");
            dbg_print(DMT_608, "%s\n",subline);
        }
        write (wb->fh, el, u);        
        //write (wb->fh, encoded_br, encoded_br_length);
        
        write (wb->fh, encoded_crlf, encoded_crlf_length);        
        begin+= strlen ((const char *) begin)+1;
    }

    sprintf ((char *) str,"</p>\n");
    if (encoding!=ENC_UNICODE)
    {
        dbg_print(DMT_608, "\r%s\n", str);
    }
    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
    write (wb->fh, enc_buffer,enc_buffer_used);
    sprintf ((char *) str,"<p begin=\"%02u:%02u:%02u,%03u\">\n\n",h2,m2,s2,ms2);
    if (encoding!=ENC_UNICODE)
    {
        dbg_print(DMT_608, "\r%s\n", str);
    }
    enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
    write (wb->fh, enc_buffer,enc_buffer_used);
    sprintf ((char *) str,"</p>\n");
}
int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context)
{
	struct spupng_t *sp = (struct spupng_t *)context->out->spupng_data;
	int x_pos, y_pos, width, height, i;
	int x, y, y_off, x_off, ret;
	uint8_t *pbuf;
	//char *filename;
	struct cc_bitmap* rect;
	png_color *palette = NULL;
	png_byte *alpha = NULL;
#ifdef ENABLE_OCR
	char*str = NULL;
#endif
	//int used;
#ifdef ENABLE_OCR
	unsigned h1,m1,s1,ms1;
	unsigned h2,m2,s2,ms2;
#endif
	LLONG start_time, end_time;
	//char timeline[128];
	int len = 0;

        x_pos = -1;
        y_pos = -1;
        width = 0;
        height = 0;

	if (context->prev_start != -1 && (sub->flags & SUB_EOD_MARKER))
	{
		start_time = context->prev_start + context->subs_delay;
		end_time = sub->start_time - 1;
	}
	else if ( !(sub->flags & SUB_EOD_MARKER))
	{
		start_time = sub->start_time + context->subs_delay;
		end_time = sub->end_time - 1;
	}

	if(sub->nb_data == 0 )
		return 0;
	rect = sub->data;
	for(i = 0;i < sub->nb_data;i++)
	{
		if(x_pos == -1)
		{
			x_pos = rect[i].x;
			y_pos = rect[i].y;
			width = rect[i].w;
			height = rect[i].h;
		}
		else
		{
			if(x_pos > rect[i].x)
			{
				width += (x_pos - rect[i].x);
				x_pos = rect[i].x;
			}

                        if (rect[i].y < y_pos)
                        {
                                height += (y_pos - rect[i].y);
                                y_pos = rect[i].y;
                        }

                        if (rect[i].x + rect[i].w > x_pos + width)
                        {
                                width = rect[i].x + rect[i].w - x_pos;
                        }

                        if (rect[i].y + rect[i].h > y_pos + height)
                        {
                                height = rect[i].y + rect[i].h - y_pos;
                        }

		}
	}
	if ( sub->flags & SUB_EOD_MARKER )
		context->prev_start =  sub->start_time;
	pbuf = (uint8_t*) malloc(width * height);
	memset(pbuf, 0x0, width * height);

	for(i = 0;i < sub->nb_data;i++)
	{
		x_off = rect[i].x - x_pos;
		y_off = rect[i].y - y_pos;
		for (y = 0; y < rect[i].h; y++)
		{
			for (x = 0; x < rect[i].w; x++)
				pbuf[((y + y_off) * width) + x_off + x] = rect[i].data[0][y * rect[i].w + x];

		}
	}
	palette = (png_color*) malloc(rect[0].nb_colors * sizeof(png_color));
	if(!palette)
	{
		ret = -1;
		goto end;
	}
        alpha = (png_byte*) malloc(rect[0].nb_colors * sizeof(png_byte));
        if(!alpha)
        {
                ret = -1;
                goto end;
        }
	/* TODO do rectangle, wise one color table should not be used for all rectangle */
        mapclut_paletee(palette, alpha, (uint32_t *)rect[0].data[1],rect[0].nb_colors);
	quantize_map(alpha, palette, pbuf, width*height, 3, rect[0].nb_colors);
#ifdef ENABLE_OCR
	str = ocr_bitmap(palette,alpha,pbuf,width,height);
	if(str && str[0])
	{
		if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER))
		{
			char *token = NULL;
			token = strtok(str,"\r\n");
			while (token)
			{

				if (ccx_options.transcript_settings.showStartTime)
				{
					char buf1[80];
					if (ccx_options.transcript_settings.relativeTimestamp)
					{
						millis_to_date(start_time + context->subs_delay, buf1);
						fdprintf(context->out->fh, "%s|", buf1);
					}
					else
					{
						mstotime(start_time + context->subs_delay, &h1, &m1, &s1, &ms1);
						time_t start_time_int = (start_time + context->subs_delay) / 1000;
						int start_time_dec = (start_time + context->subs_delay) % 1000;
						struct tm *start_time_struct = gmtime(&start_time_int);
						strftime(buf1, sizeof(buf1), "%Y%m%d%H%M%S", start_time_struct);
						fdprintf(context->out->fh, "%s%c%03d|", buf1,ccx_options.millis_separator,start_time_dec);
					}
				}

				if (ccx_options.transcript_settings.showEndTime)
				{
					char buf2[80];
					if (ccx_options.transcript_settings.relativeTimestamp)
					{
						millis_to_date(end_time, buf2);
						fdprintf(context->out->fh, "%s|", buf2);
					}
					else
					{
						mstotime(get_fts() + context->subs_delay, &h2, &m2, &s2, &ms2);
						time_t end_time_int = end_time / 1000;
						int end_time_dec = end_time % 1000;
						struct tm *end_time_struct = gmtime(&end_time_int);
						strftime(buf2, sizeof(buf2), "%Y%m%d%H%M%S", end_time_struct);
						fdprintf(context->out->fh, "%s%c%03d|", buf2,ccx_options.millis_separator,end_time_dec);
					}
				}
				if (ccx_options.transcript_settings.showCC)
				{
					fdprintf(context->out->fh,"%s|",language[sub->lang_index]);
				}
				if (ccx_options.transcript_settings.showMode)
				{
					fdprintf(context->out->fh,"DVB|");
				}
				fdprintf(context->out->fh,"%s\n",token);
				token = strtok(NULL,"\r\n");

			}

		}
	}
#endif

end:
	sub->nb_data = 0;
	freep(&sub->data);
	freep(&palette);
	freep(&alpha);
	return ret;

}