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; }
unsigned char *close_tag(unsigned char *buffer, char *tagstack, char tagtype, int *punderlined, int *pitalics, int *pchanged_font) { for (int l = strlen(tagstack) - 1; l >= 0; l--) { char cur = tagstack[l]; switch (cur) { case 'F': buffer += encode_line(buffer, (unsigned char *) "</font>"); (*pchanged_font)--; break; case 'U': buffer += encode_line(buffer, (unsigned char *) "</u>"); (*punderlined)--; break; case 'I': buffer += encode_line(buffer, (unsigned char *) "</i>"); (*pitalics)--; break; } tagstack[l] = 0; // Remove from stack if (cur == tagtype) // We closed up to the required tag, done return buffer; } if (tagtype != 'A') // All ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Mismatched tags in encoding, this is a bug, please report"); return buffer; }
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; }
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; int i = 0; char *str; ms_start = sub->start_time + context->subs_delay; ms_end = sub->end_time + context->subs_delay; if (ms_start<0) // Drop screens that because of subs_delay start too early return 0; if(sub->nb_data == 0 ) return 0; if(sub->flags & SUB_EOD_MARKER) context->prev_start = sub->start_time; str = paraof_ocrtext(sub, context->encoded_crlf, context->encoded_crlf_length); if (str) { if (context->prev_start != -1 || !(sub->flags & SUB_EOD_MARKER)) { millis_to_time (ms_start,&h1,&m1,&s1,&ms1); millis_to_time (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); write (context->out->fh, context->buffer, used); len = strlen(str); write (context->out->fh, str, len); write (context->out->fh, context->encoded_crlf, context->encoded_crlf_length); } freep(&str); } for(i = 0, rect = sub->data; i < sub->nb_data; i++, rect++) { freep(rect->data); freep(rect->data+1); } #endif sub->nb_data = 0; freep(&sub->data); return ret; }
int write_cc_buffer_as_sami(struct eia608_screen *data, struct encoder_ctx *context) { int used; LLONG startms, endms; int wrote_something=0; startms = data->start_time; startms+=context->subs_delay; if (startms<0) // Drop screens that because of subs_delay start too early return 0; endms = data->end_time; endms--; // To prevent overlapping with next line. sprintf ((char *) str, "<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n", (unsigned long long)startms); if (context->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line(context->buffer,(unsigned char *) str); write (context->out->fh, context->buffer, used); for (int i=0;i<15;i++) { if (data->row_used[i]) { int length = get_decoder_line_encoded (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); wrote_something = 1; if (i!=14) write (context->out->fh, encoded_br, encoded_br_length); write (context->out->fh, encoded_crlf, encoded_crlf_length); } } sprintf ((char *) str,"</P></SYNC>\r\n"); if (context->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line(context->buffer,(unsigned char *) str); write (context->out->fh, context->buffer, used); sprintf ((char *) str, "<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n", (unsigned long long)endms); if (context->encoding!=CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line(context->buffer,(unsigned char *) str); write (context->out->fh, context->buffer, used); return wrote_something; }
int write_subtitle_file_footer(struct encoder_ctx *ctx,struct ccx_s_write *out) { int used; int ret = 0; char str[1024]; switch (ctx->write_format) { case CCX_OF_SAMI: sprintf ((char *) str,"</BODY></SAMI>\n"); if (ctx->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line (ctx, ctx->buffer,(unsigned char *) str); ret = write(out->fh, ctx->buffer, used); if (ret != used) { mprint("WARNING: loss of data\n"); } break; case CCX_OF_SMPTETT: sprintf ((char *) str," </div>\n </body>\n</tt>\n"); if (ctx->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line (ctx, ctx->buffer,(unsigned char *) str); ret = write (out->fh, ctx->buffer, used); if (ret != used) { mprint("WARNING: loss of data\n"); } break; case CCX_OF_SPUPNG: write_spumux_footer(out); break; case CCX_OF_SIMPLE_XML: sprintf ((char *) str,"</captions>\n"); if (ctx->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line (ctx, ctx->buffer,(unsigned char *) str); ret = write (out->fh, ctx->buffer, used); if (ret != used) { mprint("WARNING: loss of data\n"); } break; default: // Nothing to do, no footer on this format break; } return ret; }
void write_subtitle_file_header(struct encoder_ctx *ctx,struct ccx_s_write *out) { int used; switch (ccx_options.write_format) { case CCX_OF_SRT: // Subrip subtitles have no header break; case CCX_OF_SAMI: // This header brought to you by McPoodle's CCASDI //fprintf_encoded (wb->fh, sami_header); REQUEST_BUFFER_CAPACITY(ctx,strlen (sami_header)*3); used=encode_line (ctx->buffer,(unsigned char *) sami_header); write (out->fh, ctx->buffer,used); break; case CCX_OF_SMPTETT: // This header brought to you by McPoodle's CCASDI //fprintf_encoded (wb->fh, sami_header); REQUEST_BUFFER_CAPACITY(ctx,strlen (smptett_header)*3); used=encode_line (ctx->buffer,(unsigned char *) smptett_header); write(out->fh, ctx->buffer, used); break; case CCX_OF_RCWT: // Write header if (ccx_options.teletext_mode == CCX_TXT_IN_USE) rcwt_header[7] = 2; // sets file format version if (ccx_options.send_to_srv) net_send_header(rcwt_header, sizeof(rcwt_header)); else write(out->fh, rcwt_header, sizeof(rcwt_header)); break; case CCX_OF_SPUPNG: write_spumux_header(out); break; case CCX_OF_TRANSCRIPT: // No header. Fall thru default: break; } }
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; }
int write_stringz_as_sami(char *string, struct encoder_ctx *context, LLONG ms_start, LLONG ms_end) { int used; int len = 0; int ret = 0; unsigned char *unescaped = NULL; unsigned char *el = NULL; sprintf ((char *) str, "<SYNC start=%llu><P class=\"UNKNOWNCC\">\r\n",(unsigned long long)ms_start); if (context->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line(context->buffer, (unsigned char *) str); ret = write (context->out->fh, context->buffer, used); if(ret != used) { return ret; } len = strlen (string); unescaped= (unsigned char *) malloc (len+1); if(!unescaped) { mprint ("In write_stringz_as_sami() - not enough memory for len %d.\n", len); ret = -1; goto end; } el = (unsigned char *) malloc (len*3+1); // Be generous if (el == NULL) { mprint ("In write_stringz_as_sami() - not enough memory for len %d.\n", len); ret = -1; goto end; } 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 (context->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r"); dbg_print(CCX_DMT_DECODER_608, "%s\n",context->subline); } ret = write(context->out->fh, el, u); if(ret != u) goto end; ret = write(context->out->fh, encoded_br, encoded_br_length); if(ret != encoded_br_length) goto end; ret = write(context->out->fh, encoded_crlf, encoded_crlf_length); if(ret != encoded_crlf_length) goto end; begin += strlen ((const char *) begin) + 1; } sprintf ((char *) str, "</P></SYNC>\r\n"); if (context->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } used = encode_line (context->buffer,(unsigned char *) str); ret = write(context->out->fh, context->buffer, used); if(ret != used) goto end; sprintf ((char *) str, "<SYNC start=%llu><P class=\"UNKNOWNCC\"> </P></SYNC>\r\n\r\n", (unsigned long long)ms_end); if (context->encoding != CCX_ENC_UNICODE) { dbg_print(CCX_DMT_DECODER_608, "\r%s\n", str); } ret = write(context->out->fh, context->buffer, used); if(ret != used) goto end; end: free(el); free(unescaped); return ret; }
unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, struct eia608_screen *data) { int col = COL_WHITE; int underlined = 0; int italics = 0; int changed_font = 0; char tagstack[128] = ""; // Keep track of opening/closing tags unsigned char *line = data->characters[line_num]; unsigned char *orig = buffer; // Keep for debugging int first = 0, last = 31; if (ccx_encoders_helpers_settings.trim_subs) find_limit_characters(line, &first, &last); for (int i = first; i <= last; i++) { // Handle color int its_col = data->colors[line_num][i]; if (its_col != col && !ccx_encoders_helpers_settings.no_font_color && !(col == COL_USERDEFINED && its_col == COL_WHITE)) // Don't replace user defined with white { if (changed_font) buffer = close_tag(buffer, tagstack, 'F', &underlined, &italics, &changed_font); // Add new font tag buffer += encode_line(buffer, (unsigned char*)color_text[its_col][1]); if (its_col == COL_USERDEFINED) { // The previous sentence doesn't copy the whole // <font> tag, just up to the quote before the color buffer += encode_line(buffer, (unsigned char*)usercolor_rgb); buffer += encode_line(buffer, (unsigned char*) "\">"); } if (color_text[its_col][1][0]) // That means a <font> was added to the buffer { strcat(tagstack, "F"); changed_font++; } col = its_col; } // Handle underlined int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED; if (is_underlined && underlined == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open underline { buffer += encode_line(buffer, (unsigned char *) "<u>"); strcat(tagstack, "U"); underlined++; } if (is_underlined == 0 && underlined && !ccx_encoders_helpers_settings.no_type_setting) // Close underline { buffer = close_tag(buffer, tagstack, 'U', &underlined, &italics, &changed_font); } // Handle italics int has_ita = data->fonts[line_num][i] & FONT_ITALICS; if (has_ita && italics == 0 && !ccx_encoders_helpers_settings.no_type_setting) // Open italics { buffer += encode_line(buffer, (unsigned char *) "<i>"); strcat(tagstack, "I"); italics++; } if (has_ita == 0 && italics && !ccx_encoders_helpers_settings.no_type_setting) // Close italics { buffer = close_tag(buffer, tagstack, 'I', &underlined, &italics, &changed_font); } int bytes = 0; switch (ccx_encoders_helpers_settings.encoding) { case CCX_ENC_UTF_8: bytes = get_char_in_utf_8(buffer, line[i]); break; case CCX_ENC_LATIN_1: get_char_in_latin_1(buffer, line[i]); bytes = 1; break; case CCX_ENC_UNICODE: get_char_in_unicode(buffer, line[i]); bytes = 2; break; } buffer += bytes; } buffer = close_tag(buffer, tagstack, 'A', &underlined, &italics, &changed_font); if (underlined || italics || changed_font) ccx_common_logging.fatal_ftn(CCX_COMMON_EXIT_BUG_BUG, "Not all tags closed in encoding, this is a bug, please report.\n"); *buffer = 0; return (unsigned)(buffer - orig); // Return length }
int main(int argc, char *argv[]) { char *c; struct encoder_ctx enc_ctx[2]; struct cc_subtitle dec_sub; #ifdef ENABLE_FFMPEG void *ffmpeg_ctx = NULL; #endif struct lib_ccx_ctx *ctx; struct lib_cc_decode *dec_ctx = NULL; init_options (&ccx_options); parse_configuration(&ccx_options); parse_parameters (&ccx_options, argc, argv); // Initialize libraries ctx = init_libraries(&ccx_options); dec_ctx = ctx->dec_ctx; // Prepare write structures init_write(&ctx->wbout1,ccx_options.wbout1.filename); init_write(&ctx->wbout2,ccx_options.wbout2.filename); int show_myth_banner = 0; memset (&cea708services[0],0,CCX_DECODERS_708_MAX_SERVICES*sizeof (int)); // Cannot (yet) be moved because it's needed in parse_parameters. memset (&dec_sub, 0,sizeof(dec_sub)); if (ctx->num_input_files==0 && ccx_options.input_source==CCX_DS_FILE) { usage (); fatal (EXIT_NO_INPUT_FILES, "(This help screen was shown because there were no input files)\n"); } if (ctx->num_input_files>1 && ccx_options.live_stream) { fatal(EXIT_TOO_MANY_INPUT_FILES, "Live stream mode accepts only one input file.\n"); } if (ctx->num_input_files && ccx_options.input_source==CCX_DS_NETWORK) { fatal(EXIT_TOO_MANY_INPUT_FILES, "UDP mode is not compatible with input files.\n"); } if (ccx_options.input_source==CCX_DS_NETWORK || ccx_options.input_source==CCX_DS_TCP) { ccx_options.buffer_input=1; // Mandatory, because each datagram must be read complete. } if (ctx->num_input_files && ccx_options.input_source==CCX_DS_TCP) { fatal(EXIT_TOO_MANY_INPUT_FILES, "TCP mode is not compatible with input files.\n"); } if (ctx->num_input_files > 0) { ctx->wbout1.multiple_files = 1; ctx->wbout1.first_input_file = ctx->inputfile[0]; ctx->wbout2.multiple_files = 1; ctx->wbout2.first_input_file = ctx->inputfile[0]; } // teletext page number out of range if ((tlt_config.page != 0) && ((tlt_config.page < 100) || (tlt_config.page > 899))) { fatal (EXIT_NOT_CLASSIFIED, "Teletext page number could not be lower than 100 or higher than 899\n"); } if (ccx_options.output_filename!=NULL) { // Use the given output file name for the field specified by // the -1, -2 switch. If -12 is used, the filename is used for // field 1. if (ccx_options.extract==2) ctx->wbout2.filename=ccx_options.output_filename; else ctx->wbout1.filename=ccx_options.output_filename; } switch (ccx_options.write_format) { case CCX_OF_RAW: ctx->extension = ".raw"; break; case CCX_OF_SRT: ctx->extension = ".srt"; break; case CCX_OF_SAMI: ctx->extension = ".smi"; break; case CCX_OF_SMPTETT: ctx->extension = ".ttml"; break; case CCX_OF_TRANSCRIPT: ctx->extension = ".txt"; break; case CCX_OF_RCWT: ctx->extension = ".bin"; break; case CCX_OF_SPUPNG: ctx->extension = ".xml"; break; case CCX_OF_NULL: ctx->extension = ""; break; case CCX_OF_DVDRAW: ctx->extension = ".dvdraw"; break; default: fatal (CCX_COMMON_EXIT_BUG_BUG, "write_format doesn't have any legal value, this is a bug.\n"); } params_dump(ctx); // default teletext page if (tlt_config.page > 0) { // dec to BCD, magazine pages numbers are in BCD (ETSI 300 706) tlt_config.page = ((tlt_config.page / 100) << 8) | (((tlt_config.page / 10) % 10) << 4) | (tlt_config.page % 10); } if (ctx->auto_stream==CCX_SM_MCPOODLESRAW && ccx_options.write_format==CCX_OF_RAW) { fatal (EXIT_INCOMPATIBLE_PARAMETERS, "-in=raw can only be used if the output is a subtitle file.\n"); } if (ctx->auto_stream==CCX_SM_RCWT && ccx_options.write_format==CCX_OF_RCWT && ccx_options.output_filename==NULL) { fatal (EXIT_INCOMPATIBLE_PARAMETERS, "CCExtractor's binary format can only be used simultaneously for input and\noutput if the output file name is specified given with -o.\n"); } subline = (unsigned char *) malloc (SUBLINESIZE); switch (ccx_options.input_source) { case CCX_DS_FILE: ctx->basefilename = (char *) malloc (strlen (ctx->inputfile[0])+1); break; case CCX_DS_STDIN: ctx->basefilename = (char *) malloc (strlen (ctx->basefilename_for_stdin)+1); break; case CCX_DS_NETWORK: case CCX_DS_TCP: ctx->basefilename = (char *) malloc (strlen (ctx->basefilename_for_network)+1); break; } if (ctx->basefilename == NULL) fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n"); switch (ccx_options.input_source) { case CCX_DS_FILE: strcpy (ctx->basefilename, ctx->inputfile[0]); break; case CCX_DS_STDIN: strcpy (ctx->basefilename, ctx->basefilename_for_stdin); break; case CCX_DS_NETWORK: case CCX_DS_TCP: strcpy (ctx->basefilename, ctx->basefilename_for_network); break; } for (c=ctx->basefilename+strlen (ctx->basefilename)-1; ctx->basefilename && *c!='.'; c--) {;} // Get last . if (*c=='.') *c=0; if (ctx->wbout1.filename==NULL) { ctx->wbout1.filename = (char *) malloc (strlen (ctx->basefilename)+3+strlen (ctx->extension)); ctx->wbout1.filename[0]=0; } if (ctx->wbout2.filename==NULL) { ctx->wbout2.filename = (char *) malloc (strlen (ctx->basefilename)+3+strlen (ctx->extension)); ctx->wbout2.filename[0]=0; } if (ctx->buffer == NULL || ctx->pesheaderbuf==NULL || ctx->wbout1.filename == NULL || ctx->wbout2.filename == NULL || subline==NULL || init_file_buffer() ) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n"); } if (ccx_options.send_to_srv) { connect_to_srv(ccx_options.srv_addr, ccx_options.srv_port, ccx_options.tcp_desc); } if (ccx_options.write_format!=CCX_OF_NULL) { /* # DVD format uses one raw file for both fields, while Broadcast requires 2 */ if (ccx_options.write_format==CCX_OF_DVDRAW) { if (ctx->wbout1.filename[0]==0) { strcpy (ctx->wbout1.filename,ctx->basefilename); strcat (ctx->wbout1.filename,".raw"); } if (ctx->cc_to_stdout) { ctx->wbout1.fh=STDOUT_FILENO; mprint ("Sending captions to stdout.\n"); } else { mprint ("Creating %s\n", ctx->wbout1.filename); ctx->wbout1.fh=open (ctx->wbout1.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE); if (ctx->wbout1.fh==-1) { fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed\n"); } } } else { if (ctx->cc_to_stdout && ccx_options.extract==12) fatal (EXIT_INCOMPATIBLE_PARAMETERS, "You can't extract both fields to stdout at the same time in broadcast mode."); if (ccx_options.write_format == CCX_OF_SPUPNG && ctx->cc_to_stdout) fatal (EXIT_INCOMPATIBLE_PARAMETERS, "You cannot use -out=spupng with -stdout."); if (ccx_options.extract!=2) { if (ctx->cc_to_stdout) { ctx->wbout1.fh=STDOUT_FILENO; mprint ("Sending captions to stdout.\n"); } else if (!ccx_options.send_to_srv) { if (ctx->wbout1.filename[0]==0) { strcpy (ctx->wbout1.filename,ctx->basefilename); if (ccx_options.extract==12) // _1 only added if there's two files strcat (ctx->wbout1.filename,"_1"); strcat (ctx->wbout1.filename,(const char *) ctx->extension); } mprint ("Creating %s\n", ctx->wbout1.filename); ctx->wbout1.fh=open (ctx->wbout1.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE); if (ctx->wbout1.fh==-1) { fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed (errno=%d)\n", errno); } } switch (ccx_options.write_format) { case CCX_OF_RAW: writeraw(BROADCAST_HEADER, sizeof(BROADCAST_HEADER), &ctx->wbout1); break; case CCX_OF_DVDRAW: break; case CCX_OF_RCWT: if (init_encoder(enc_ctx, &ctx->wbout1)) fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n"); set_encoder_subs_delay(enc_ctx, ctx->subs_delay); set_encoder_last_displayed_subs_ms(enc_ctx, ctx->last_displayed_subs_ms); set_encoder_startcredits_displayed(enc_ctx, ctx->startcredits_displayed); break; default: if (!ccx_options.no_bom){ if (ccx_options.encoding == CCX_ENC_UTF_8){ // Write BOM writeraw(UTF8_BOM, sizeof(UTF8_BOM), &ctx->wbout1); } if (ccx_options.encoding == CCX_ENC_UNICODE){ // Write BOM writeraw(LITTLE_ENDIAN_BOM, sizeof(LITTLE_ENDIAN_BOM), &ctx->wbout1); } } if (init_encoder(enc_ctx, &ctx->wbout1)){ fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n"); } set_encoder_subs_delay(enc_ctx, ctx->subs_delay); set_encoder_last_displayed_subs_ms(enc_ctx, ctx->last_displayed_subs_ms); set_encoder_startcredits_displayed(enc_ctx, ctx->startcredits_displayed); } } if (ccx_options.extract == 12 && ccx_options.write_format != CCX_OF_RAW) mprint (" and \n"); if (ccx_options.extract!=1) { if (ctx->cc_to_stdout) { ctx->wbout1.fh=STDOUT_FILENO; mprint ("Sending captions to stdout.\n"); } else if(ccx_options.write_format == CCX_OF_RAW && ccx_options.extract == 12) { memcpy(&ctx->wbout2, &ctx->wbout1,sizeof(ctx->wbout1)); } else if (!ccx_options.send_to_srv) { if (ctx->wbout2.filename[0]==0) { strcpy (ctx->wbout2.filename,ctx->basefilename); if (ccx_options.extract==12) // _ only added if there's two files strcat (ctx->wbout2.filename,"_2"); strcat (ctx->wbout2.filename,(const char *) ctx->extension); } mprint ("Creating %s\n", ctx->wbout2.filename); ctx->wbout2.fh=open (ctx->wbout2.filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE); if (ctx->wbout2.fh==-1) { fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Failed\n"); } if(ccx_options.write_format == CCX_OF_RAW) writeraw (BROADCAST_HEADER,sizeof (BROADCAST_HEADER),&ctx->wbout2); } switch (ccx_options.write_format) { case CCX_OF_RAW: case CCX_OF_DVDRAW: break; case CCX_OF_RCWT: if( init_encoder(enc_ctx+1,&ctx->wbout2) ) fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n"); set_encoder_subs_delay(enc_ctx+1, ctx->subs_delay); set_encoder_last_displayed_subs_ms(enc_ctx+1, ctx->last_displayed_subs_ms); set_encoder_startcredits_displayed(enc_ctx+1, ctx->startcredits_displayed); break; default: if (!ccx_options.no_bom){ if (ccx_options.encoding == CCX_ENC_UTF_8){ // Write BOM writeraw(UTF8_BOM, sizeof(UTF8_BOM), &ctx->wbout2); } if (ccx_options.encoding == CCX_ENC_UNICODE){ // Write BOM writeraw(LITTLE_ENDIAN_BOM, sizeof(LITTLE_ENDIAN_BOM), &ctx->wbout2); } } if (init_encoder(enc_ctx + 1, &ctx->wbout2)){ fatal(EXIT_NOT_ENOUGH_MEMORY, "Not enough memory\n"); } set_encoder_subs_delay(enc_ctx+1, ctx->subs_delay); set_encoder_last_displayed_subs_ms(enc_ctx+1, ctx->last_displayed_subs_ms); set_encoder_startcredits_displayed(enc_ctx+1, ctx->startcredits_displayed); } } } } if (ccx_options.transcript_settings.xds) { if (ccx_options.write_format != CCX_OF_TRANSCRIPT) { ccx_options.transcript_settings.xds = 0; mprint ("Warning: -xds ignored, XDS can only be exported to transcripts at this time.\n"); } } if (ccx_options.teletext_mode == CCX_TXT_IN_USE) // Here, it would mean it was forced by user telxcc_init(ctx); ctx->fh_out_elementarystream = NULL; if (ccx_options.out_elementarystream_filename!=NULL) { if ((ctx->fh_out_elementarystream = fopen (ccx_options.out_elementarystream_filename,"wb"))==NULL) { fatal(CCX_COMMON_EXIT_FILE_CREATION_FAILED, "Unable to open clean file: %s\n", ccx_options.out_elementarystream_filename); } } // Initialize HDTV caption buffer init_hdcc(); if (ccx_options.line_terminator_lf) encoded_crlf_length = encode_line(encoded_crlf, (unsigned char *) "\n"); else encoded_crlf_length = encode_line(encoded_crlf, (unsigned char *) "\r\n"); encoded_br_length = encode_line(encoded_br, (unsigned char *) "<br>"); time_t start, final; time(&start); dec_ctx->processed_enough=0; if (ccx_options.binary_concat) { ctx->total_inputsize=gettotalfilessize(ctx); if (ctx->total_inputsize==-1) fatal (EXIT_UNABLE_TO_DETERMINE_FILE_SIZE, "Failed to determine total file size.\n"); } #ifndef _WIN32 signal_ctx = ctx; m_signal(SIGINT, sigint_handler); #endif while (switch_to_next_file(ctx, 0) && !dec_ctx->processed_enough) { prepare_for_new_file(ctx); #ifdef ENABLE_FFMPEG close_input_file(ctx); ffmpeg_ctx = init_ffmpeg(ctx->inputfile[0]); if(ffmpeg_ctx) { do { int ret = 0; unsigned char *bptr = ctx->buffer; int len = ff_get_ccframe(ffmpeg_ctx, bptr, 1024); int cc_count = 0; if(len == AVERROR(EAGAIN)) { continue; } else if(len == AVERROR_EOF) break; else if(len == 0) continue; else if(len < 0 ) { mprint("Error extracting Frame\n"); break; } else cc_count = len/3; ret = process_cc_data(dec_ctx, bptr, cc_count, &dec_sub); if(ret >= 0 && dec_sub.got_output) { encode_sub(enc_ctx, &dec_sub); dec_sub.got_output = 0; } }while(1); continue; } else { mprint ("\rFailed to initialized ffmpeg falling back to legacy\n"); } #endif if (ctx->auto_stream == CCX_SM_AUTODETECT) { detect_stream_type(ctx); switch (ctx->stream_mode) { case CCX_SM_ELEMENTARY_OR_NOT_FOUND: mprint ("\rFile seems to be an elementary stream, enabling ES mode\n"); break; case CCX_SM_TRANSPORT: mprint ("\rFile seems to be a transport stream, enabling TS mode\n"); break; case CCX_SM_PROGRAM: mprint ("\rFile seems to be a program stream, enabling PS mode\n"); break; case CCX_SM_ASF: mprint ("\rFile seems to be an ASF, enabling DVR-MS mode\n"); break; case CCX_SM_WTV: mprint ("\rFile seems to be a WTV, enabling WTV mode\n"); break; case CCX_SM_MCPOODLESRAW: mprint ("\rFile seems to be McPoodle raw data\n"); break; case CCX_SM_RCWT: mprint ("\rFile seems to be a raw caption with time data\n"); break; case CCX_SM_MP4: mprint ("\rFile seems to be a MP4\n"); break; #ifdef WTV_DEBUG case CCX_SM_HEX_DUMP: mprint ("\rFile seems to be an hexadecimal dump\n"); break; #endif case CCX_SM_MYTH: case CCX_SM_AUTODETECT: fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!"); break; } } else { ctx->stream_mode=ctx->auto_stream; } /* ----------------------------------------------------------------- MAIN LOOP ----------------------------------------------------------------- */ // The myth loop autodetect will only be used with ES or PS streams switch (ccx_options.auto_myth) { case 0: // Use whatever stream mode says break; case 1: // Force stream mode to myth ctx->stream_mode=CCX_SM_MYTH; break; case 2: // autodetect myth files, but only if it does not conflict with // the current stream mode switch (ctx->stream_mode) { case CCX_SM_ELEMENTARY_OR_NOT_FOUND: case CCX_SM_PROGRAM: if ( detect_myth(ctx) ) { ctx->stream_mode=CCX_SM_MYTH; } break; default: // Keep stream_mode break; } break; } // Disable sync check for raw formats - they have the right timeline. // Also true for bin formats, but -nosync might have created a // broken timeline for debug purposes. // Disable too in MP4, specs doesn't say that there can't be a jump switch (ctx->stream_mode) { case CCX_SM_MCPOODLESRAW: case CCX_SM_RCWT: case CCX_SM_MP4: #ifdef WTV_DEBUG case CCX_SM_HEX_DUMP: #endif ccx_common_timing_settings.disable_sync_check = 1; break; default: break; } switch (ctx->stream_mode) { case CCX_SM_ELEMENTARY_OR_NOT_FOUND: if (!ccx_options.use_gop_as_pts) // If !0 then the user selected something ccx_options.use_gop_as_pts = 1; // Force GOP timing for ES ccx_common_timing_settings.is_elementary_stream = 1; case CCX_SM_TRANSPORT: case CCX_SM_PROGRAM: case CCX_SM_ASF: case CCX_SM_WTV: if (!ccx_options.use_gop_as_pts) // If !0 then the user selected something ccx_options.use_gop_as_pts = 0; mprint ("\rAnalyzing data in general mode\n"); general_loop(ctx, &enc_ctx); break; case CCX_SM_MCPOODLESRAW: mprint ("\rAnalyzing data in McPoodle raw mode\n"); raw_loop(ctx, &enc_ctx); break; case CCX_SM_RCWT: mprint ("\rAnalyzing data in CCExtractor's binary format\n"); rcwt_loop(ctx, &enc_ctx); break; case CCX_SM_MYTH: mprint ("\rAnalyzing data in MythTV mode\n"); show_myth_banner = 1; myth_loop(ctx, &enc_ctx); break; case CCX_SM_MP4: mprint ("\rAnalyzing data with GPAC (MP4 library)\n"); close_input_file(ctx); // No need to have it open. GPAC will do it for us processmp4 (ctx, ctx->inputfile[0],&enc_ctx); break; #ifdef WTV_DEBUG case CCX_SM_HEX_DUMP: close_input_file(ctx); // processhex will open it in text mode processhex (ctx, ctx->inputfile[0]); break; #endif case CCX_SM_AUTODETECT: fatal(CCX_COMMON_EXIT_BUG_BUG, "Cannot be reached!"); break; } mprint("\n"); dbg_print(CCX_DMT_DECODER_608, "\nTime stamps after last caption block was written:\n"); dbg_print(CCX_DMT_DECODER_608, "Last time stamps: PTS: %s (%+2dF) ", print_mstime( (LLONG) (sync_pts/(MPEG_CLOCK_FREQ/1000) +frames_since_ref_time*1000.0/current_fps) ), frames_since_ref_time); dbg_print(CCX_DMT_DECODER_608, "GOP: %s \n", print_mstime(gop_time.ms) ); // Blocks since last PTS/GOP time stamp. dbg_print(CCX_DMT_DECODER_608, "Calc. difference: PTS: %s (%+3lldms incl.) ", print_mstime( (LLONG) ((sync_pts-min_pts)/(MPEG_CLOCK_FREQ/1000) + fts_offset + frames_since_ref_time*1000.0/current_fps)), fts_offset + (LLONG) (frames_since_ref_time*1000.0/current_fps) ); dbg_print(CCX_DMT_DECODER_608, "GOP: %s (%+3dms incl.)\n", print_mstime((LLONG)(gop_time.ms -first_gop_time.ms +get_fts_max()-fts_at_gop_start)), (int)(get_fts_max()-fts_at_gop_start)); // When padding is active the CC block time should be within // 1000/29.97 us of the differences. dbg_print(CCX_DMT_DECODER_608, "Max. FTS: %s (without caption blocks since then)\n", print_mstime(get_fts_max())); if (ctx->stat_hdtv) { mprint ("\rCC type 0: %d (%s)\n", dec_ctx->cc_stats[0], cc_types[0]); mprint ("CC type 1: %d (%s)\n", dec_ctx->cc_stats[1], cc_types[1]); mprint ("CC type 2: %d (%s)\n", dec_ctx->cc_stats[2], cc_types[2]); mprint ("CC type 3: %d (%s)\n", dec_ctx->cc_stats[3], cc_types[3]); } mprint ("\nTotal frames time: %s (%u frames at %.2ffps)\n", print_mstime( (LLONG)(total_frames_count*1000/current_fps) ), total_frames_count, current_fps); if (ctx->total_pulldownframes) mprint ("incl. pulldown frames: %s (%u frames at %.2ffps)\n", print_mstime( (LLONG)(ctx->total_pulldownframes*1000/current_fps) ), ctx->total_pulldownframes, current_fps); if (pts_set >= 1 && min_pts != 0x01FFFFFFFFLL) { LLONG postsyncms = (LLONG) (ctx->frames_since_last_gop*1000/current_fps); mprint ("\nMin PTS: %s\n", print_mstime( min_pts/(MPEG_CLOCK_FREQ/1000) - fts_offset)); if (pts_big_change) mprint ("(Reference clock was reset at some point, Min PTS is approximated)\n"); mprint ("Max PTS: %s\n", print_mstime( sync_pts/(MPEG_CLOCK_FREQ/1000) + postsyncms)); mprint ("Length: %s\n", print_mstime( sync_pts/(MPEG_CLOCK_FREQ/1000) + postsyncms - min_pts/(MPEG_CLOCK_FREQ/1000) + fts_offset )); } // dvr-ms files have invalid GOPs if (gop_time.inited && first_gop_time.inited && ctx->stream_mode != CCX_SM_ASF) { mprint ("\nInitial GOP time: %s\n", print_mstime(first_gop_time.ms)); mprint ("Final GOP time: %s%+3dF\n", print_mstime(gop_time.ms), ctx->frames_since_last_gop); mprint ("Diff. GOP length: %s%+3dF", print_mstime(gop_time.ms - first_gop_time.ms), ctx->frames_since_last_gop); mprint (" (%s)\n", print_mstime(gop_time.ms - first_gop_time.ms +(LLONG) ((ctx->frames_since_last_gop)*1000/29.97)) ); } if (ctx->false_pict_header) mprint ("\nNumber of likely false picture headers (discarded): %d\n",ctx->false_pict_header); if (ctx->stat_numuserheaders) mprint("\nTotal user data fields: %d\n", ctx->stat_numuserheaders); if (ctx->stat_dvdccheaders) mprint("DVD-type user data fields: %d\n", ctx->stat_dvdccheaders); if (ctx->stat_scte20ccheaders) mprint("SCTE-20 type user data fields: %d\n", ctx->stat_scte20ccheaders); if (ctx->stat_replay4000headers) mprint("ReplayTV 4000 user data fields: %d\n", ctx->stat_replay4000headers); if (ctx->stat_replay5000headers) mprint("ReplayTV 5000 user data fields: %d\n", ctx->stat_replay5000headers); if (ctx->stat_hdtv) mprint("HDTV type user data fields: %d\n", ctx->stat_hdtv); if (ctx->stat_dishheaders) mprint("Dish Network user data fields: %d\n", ctx->stat_dishheaders); if (ctx->stat_divicom) { mprint("CEA608/Divicom user data fields: %d\n", ctx->stat_divicom); mprint("\n\nNOTE! The CEA 608 / Divicom standard encoding for closed\n"); mprint("caption is not well understood!\n\n"); mprint("Please submit samples to the developers.\n\n\n"); } // Add one frame as fts_max marks the beginning of the last frame, // but we need the end. fts_global += fts_max + (LLONG) (1000.0/current_fps); // CFS: At least in Hauppage mode, cb_field can be responsible for ALL the // timing (cb_fields having a huge number and fts_now and fts_global being 0 all // the time), so we need to take that into account in fts_global before resetting // counters. if (cb_field1!=0) fts_global += cb_field1*1001/3; else fts_global += cb_field2*1001/3; // Reset counters - This is needed if some captions are still buffered // and need to be written after the last file is processed. cb_field1 = 0; cb_field2 = 0; cb_708 = 0; fts_now = 0; fts_max = 0; } // file loop close_input_file(ctx); if (ctx->fh_out_elementarystream!=NULL) fclose (ctx->fh_out_elementarystream); flushbuffer (ctx, &ctx->wbout1, false); flushbuffer (ctx, &ctx->wbout2, false); prepare_for_new_file (ctx); // To reset counters used by handle_end_of_data() telxcc_close(ctx); if (ctx->wbout1.fh!=-1) { if (ccx_options.write_format==CCX_OF_SMPTETT || ccx_options.write_format==CCX_OF_SAMI || ccx_options.write_format==CCX_OF_SRT || ccx_options.write_format==CCX_OF_TRANSCRIPT || ccx_options.write_format==CCX_OF_SPUPNG ) { handle_end_of_data(dec_ctx->context_cc608_field_1, &dec_sub); if (dec_sub.got_output) { encode_sub(enc_ctx,&dec_sub); dec_sub.got_output = 0; } } else if(ccx_options.write_format==CCX_OF_RCWT) { // Write last header and data writercwtdata (dec_ctx, NULL); } dinit_encoder(enc_ctx); } if (ctx->wbout2.fh!=-1) { if (ccx_options.write_format==CCX_OF_SMPTETT || ccx_options.write_format==CCX_OF_SAMI || ccx_options.write_format==CCX_OF_SRT || ccx_options.write_format==CCX_OF_TRANSCRIPT || ccx_options.write_format==CCX_OF_SPUPNG ) { handle_end_of_data(dec_ctx->context_cc608_field_2, &dec_sub); if (dec_sub.got_output) { encode_sub(enc_ctx,&dec_sub); dec_sub.got_output = 0; } } dinit_encoder(enc_ctx+1); } flushbuffer (ctx, &ctx->wbout1,true); flushbuffer (ctx, &ctx->wbout2,true); time (&final); long proc_time=(long) (final-start); mprint ("\rDone, processing time = %ld seconds\n", proc_time); if (proc_time>0) { LLONG ratio=(get_fts_max()/10)/proc_time; unsigned s1=(unsigned) (ratio/100); unsigned s2=(unsigned) (ratio%100); mprint ("Performance (real length/process time) = %u.%02u\n", s1, s2); } dbg_print(CCX_DMT_708, "The 708 decoder was reset [%d] times.\n",resets_708); if (ccx_options.teletext_mode == CCX_TXT_IN_USE) mprint ( "Teletext decoder: %"PRIu32" packets processed, %"PRIu32" SRT frames written.\n", tlt_packet_counter, tlt_frames_produced); if (dec_ctx->processed_enough) { mprint ("\rNote: Processing was cancelled before all data was processed because\n"); mprint ("\rone or more user-defined limits were reached.\n"); } if (ccblocks_in_avc_lost>0) { mprint ("Total caption blocks received: %d\n", ccblocks_in_avc_total); mprint ("Total caption blocks lost: %d\n", ccblocks_in_avc_lost); } mprint ("This is beta software. Report issues to carlos at ccextractor org...\n"); if (show_myth_banner) { mprint ("NOTICE: Due to the major rework in 0.49, we needed to change part of the timing\n"); mprint ("code in the MythTV's branch. Please report results to the address above. If\n"); mprint ("something is broken it will be fixed. Thanks\n"); } dinit_libraries(&ctx); return EXIT_OK; }
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; }
static int write_subtitle_file_header(struct encoder_ctx *ctx, struct ccx_s_write *out) { int used; int ret = 0; int header_size = 0; switch (ctx->write_format) { case CCX_OF_SRT: // Subrip subtitles have no header case CCX_OF_G608: ret = write_bom(ctx, out); if(ret < 0) return -1; break; case CCX_OF_SSA: ret = write_bom(ctx, out); if(ret < 0) return -1; REQUEST_BUFFER_CAPACITY(ctx,strlen (ssa_header)*3); used = encode_line (ctx, ctx->buffer,(unsigned char *) ssa_header); ret = write (out->fh, ctx->buffer, used); if(ret < used) { mprint("WARNING: Unable to write complete Buffer \n"); return -1; } break; case CCX_OF_WEBVTT: ret = write_bom(ctx, out); if (ret < 0) return -1; for(int i = 0; webvtt_header[i]!=NULL ;i++) { header_size += strlen(webvtt_header[i]); // Find total size of the header } REQUEST_BUFFER_CAPACITY(ctx, header_size*3); for(int i = 0; webvtt_header[i]!=NULL;i++) { if(ccx_options.enc_cfg.line_terminator_lf == 1 && strcmp(webvtt_header[i],"\r\n")==0) // If -lf parameter passed, write LF instead of CRLF { used = encode_line (ctx, ctx->buffer,(unsigned char *) "\n"); } else { used = encode_line (ctx, ctx->buffer,(unsigned char *) webvtt_header[i]); } ret = write (out->fh, ctx->buffer,used); if(ret < used) { mprint("WARNING: Unable to write complete Buffer \n"); return -1; } } break; case CCX_OF_SAMI: // This header brought to you by McPoodle's CCASDI //fprintf_encoded (wb->fh, sami_header); ret = write_bom(ctx, out); if(ret < 0) return -1; REQUEST_BUFFER_CAPACITY(ctx,strlen (sami_header)*3); used = encode_line (ctx, ctx->buffer,(unsigned char *) sami_header); ret = write (out->fh, ctx->buffer, used); if(ret < used) { mprint("WARNING: Unable to write complete Buffer \n"); return -1; } break; case CCX_OF_SMPTETT: // This header brought to you by McPoodle's CCASDI //fprintf_encoded (wb->fh, sami_header); ret = write_bom(ctx, out); if(ret < 0) return -1; REQUEST_BUFFER_CAPACITY(ctx,strlen (smptett_header)*3); used=encode_line (ctx, ctx->buffer,(unsigned char *) smptett_header); ret = write(out->fh, ctx->buffer, used); if(ret < used) { mprint("WARNING: Unable to write complete Buffer \n"); return -1; } break; case CCX_OF_RCWT: // Write header rcwt_header[7] = ctx->in_fileformat; // sets file format version if (ctx->send_to_srv) net_send_header(rcwt_header, sizeof(rcwt_header)); else { ret = write(out->fh, rcwt_header, sizeof(rcwt_header)); if(ret < 0) { mprint("Unable to write rcwt header\n"); return -1; } } break; case CCX_OF_RAW: ret = write(out->fh,BROADCAST_HEADER, sizeof(BROADCAST_HEADER)); if(ret < sizeof(BROADCAST_HEADER)) { mprint("Unable to write Raw header\n"); return -1; } break; case CCX_OF_SPUPNG: ret = write_bom(ctx, out); if(ret < 0) return -1; write_spumux_header(ctx, out); break; case CCX_OF_TRANSCRIPT: // No header. Fall thru ret = write_bom(ctx, out); if(ret < 0) return -1; break; case CCX_OF_SIMPLE_XML: // No header. Fall thru ret = write_bom(ctx, out); if(ret < 0) return -1; REQUEST_BUFFER_CAPACITY(ctx,strlen (simple_xml_header)*3); used=encode_line (ctx, ctx->buffer,(unsigned char *) simple_xml_header); ret = write(out->fh, ctx->buffer, used); if(ret < used) { mprint("WARNING: Unable to write complete Buffer \n"); return -1; } break; default: break; } return ret; }
/*** End of Protocol Prototype ***/ int handle_command(int sock, char *cmd, FILE *fptr, struct config_params *params, struct city **headlist, int *auth_success) { int counter; char commandname[MAXLEN];//also used for return:command char tablename[MAXLEN];//also used for return:status char keyname[MAXLEN]; char valuename[MAXLEN];//also used for return:secondstatus (may be detail OR value) char retline[MAXLEN]; char encoded_value[MAXLEN]; //char returncmd[MAXLEN+1]; //To send back to client time_t rawtime; struct tm * timeinfo; int index = 0; int tempcmd = 1; int tempcommand = 0; int i = 0;//common-purpose counter printf("command received: %s\n", cmd); while(cmd[tempcmd] != '&'){ if(cmd[tempcmd] != '&'){ commandname[tempcommand] = cmd[tempcmd]; tempcommand++; tempcmd++; } } commandname[tempcommand] = '\0'; tempcommand = 0; tempcmd++; tempcmd++; while(cmd[tempcmd] != '^'){ tablename[tempcommand] = cmd[tempcmd]; tempcommand++; tempcmd++; } tablename[tempcommand] = '\0'; tempcommand = 0; tempcmd++; while(cmd[tempcmd] != '\0'){ valuename[tempcommand] = cmd[tempcmd]; tempcommand++; tempcmd++; } valuename[tempcommand] = '\0'; tempcommand = 0; if(strcmp(commandname, "QUERY") == 0){ printf("command is: %s\n", commandname); printf("table is: %s\n", tablename); printf("valuename: %s\n", valuename); } else { decode_line(cmd, commandname, tablename, keyname, valuename, &counter); } //printf("commandname: %s\n", commandname); //printf("tablename: %s\n", tablename); //printf("keyname: %s\n", keyname); //printf("valuename: %s\n", valuename); char namegen[MAXLEN+1]; if(LOGGING==2){ char tempstr[MAXLEN+1]; time(&rawtime); timeinfo=localtime(&rawtime); sprintf(namegen,"%.4d-%.2d-%.2d-%.2d-%.2d-%.2d: ",timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday,timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec); //sprintf(tempstr,"Processing command '%s'\n",commandname); printf("Processing line \"%s\"\n", cmd); logger(fptr,namegen);//Timestamp logger(fptr,tempstr); } else if(LOGGING==1){ time(&rawtime); timeinfo=localtime(&rawtime); sprintf(namegen,"%.4d-%.2d-%.2d-%.2d-%.2d-%.2d: ",timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday,timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec); printf("%s",namegen);//Timestamp //printf("Processing command '%s'\n",commandname); printf("Processing line \"%s\"\n", cmd); } if (strcmp(commandname, "SET") == 0){ pthread_mutex_lock( &setMutex ); //SET below // check if authorized if ((*auth_success) == 0){ //printf("inside if statement.\n"); //strncpy(success, "AUTH", sizeof(success)); //sendall(sock, success, sizeof(success)); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, "AUTH"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } else { index = find_index(params->tablelist, tablename); if(index != -1){ //name found struct city *head = headlist[index]; struct city *temp = find_city(head, keyname); printf("valuename: %s\n", valuename); if(temp == NULL){ //entry doesn't exist if(strcmp(valuename, "@NULL@?") == 0){ //deleting a key that doesn't exist //sprintf(success, "SET$KEY"); //sendall(sock, success, sizeof(success)); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, "KEY"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } else{ int column_count = 0; column_count = count_column(valuename); if (params->num_columns[index] == column_count) { insert_city(headlist[index], keyname, valuename); //VALUE IS INSERTED AS A STRING cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "SUCCESS"); sprintf(valuename, "CREATE"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } else { sprintf(retline, "SET FAIL COLUMN\n"); sendall(sock, retline, sizeof(retline)); } } } else { //entry exists, temp != NULL if(strcmp(valuename, "@NULL@?") == 0){ //delete //printf("delete entry\n"); delete_city(&head, keyname); temp = NULL; //sprintf(success, "SET$SUCCESS"); //sendall(sock, success, sizeof(success)); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "SUCCESS"); sprintf(valuename, "DELETE"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } else{ //modify record //strncpy(temp->population, , sizeof(temp->population)); //sprintf(success, "SET$SUCCESS"); //sendall(sock, success, sizeof(success)); //printf("valuename: %s\n", valuename); if (counter == temp->counter || counter == 0) { int column_count = 0; temp = find_city(headlist[index], keyname); column_count = count_column(valuename); if (temp->numocolumns == column_count) { modify_city(temp, valuename); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "SUCCESS"); sprintf(valuename, "MODIFY"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } else { sprintf(retline, "SET FAIL COLUMN\n"); sendall(sock, retline, sizeof(retline)); } } else { char temp[100]; sprintf(temp, "%s", "SET FAIL COUNTER"); sendall(sock, temp, sizeof(temp)); } } } } else { //table doesn't exist //strncpy(fail, "SET$TABLE", sizeof(fail)); //sendall(sock, fail, sizeof(fail)); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, "TABLE"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } } pthread_mutex_unlock( &setMutex ); } // For now, just send back the command to the client. //command cases: get, set else if(strcmp(commandname, "AUTH") == 0){ //AUTH below if(strcmp(tablename, params->username) == 0){ if (strcmp(keyname, params->password) == 0){ (*auth_success) = 1; printf("authenticated\n"); //strncpy(success, "AUTH$SUCCESS", sizeof(success)); //sendall(sock, success, sizeof(success)); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "SUCCESS"); sprintf(valuename, " "); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } else { printf("authenticated\n"); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, " "); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); //strncpy(fail, "AUTH$FAIL", sizeof(fail)); //sendall(sock, fail, sizeof(fail)); } } else { cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, ""); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); //strncpy(fail, "AUTH$FAIL", sizeof(fail)); //sendall(sock, fail, sizeof(fail)); } } else if(strcmp(commandname, "GET") == 0){ // check if authenticated if ((*auth_success) == 0){ //not authenticated cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, "AUTH"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); //strncpy(success, "AUTH", sizeof(success)); //sendall(sock, success, sizeof(success)); } printf("tablename: %s\n", tablename); index=find_index(params->tablelist, tablename); printf("index: %d\n", index); if(index != -1) { //name found struct city *head = (headlist)[index]; print_city(head); struct city *temp = find_city(head, keyname); //printf("temp key: %s\n", temp->name); //printf("temp colnum: %d\n", temp->numocolumns); if(temp == NULL){ //key doesn't exist //strncpy(fail, "GET$KEY$FAIL$FAIL", sizeof(fail)); //sendall(sock, fail, sizeof(fail)) cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, "KEY"); //printf("key doesn't exist\n"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); } else { //key exists //printf("columnlist: %s\n", temp->columnlist); //printf("encoded_value: %s\n", encoded_value); //printf("temp->numocolumns: %d\n", temp->numocolumns); cleanstring(encoded_value); encode_retval(temp->columnlist, encoded_value, temp->numocolumns); cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "SUCCESS"); sprintf(valuename, "%s", encoded_value); printf("serverside\n"); printf("tablename: %s\n", tablename); printf("valuename: %s\n", valuename); encode_line(commandname, tablename, valuename, retline); char temp_str[100]; char number[100]; strcpy(temp_str, " COUNTER "); sprintf(number, "%d", temp->counter); strcat(temp_str, number); strcat(retline, temp_str); sendall(sock, retline, sizeof(retline)); //sprintf(success, "GET$SUCCESS$%s$%s", temp->name, temp->population); //sendall(sock, success, sizeof(success)); } } else { //table doesn't exist cleanstring(tablename); cleanstring(valuename); sprintf(tablename, "FAIL"); sprintf(valuename, "TABLE"); encode_line(commandname, tablename, valuename, retline); sendall(sock, retline, sizeof(retline)); //strncpy(fail, "GET$TABLE$FAIL$FAIL", sizeof(fail)); //sendall(sock, fail, sizeof(fail)); } } else if(strcmp(commandname, "QUERY") == 0) {//query //what to do? //first allocate a keylist //then do searching //when done, encode the keylist and send back to client puts("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$HANDLEQUERY$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"); struct queryarg *testque = (struct queryarg *)malloc(sizeof(struct queryarg)); int numque = 0; int questatus = 0; char server_keylist[1000][1024]; for(i = 0; i < 1000; i++){ cleanstring(server_keylist[i]); } strncpy(server_keylist[0], "testcopy", sizeof(server_keylist[0])); index = find_index(params->tablelist, tablename); //printf("index is %d\n", index); if(index != -1){ //found matching name in tablelist struct city *node = (headlist)[index]; numque = query_argument(testque, valuename); //printf("numque = %d\n", numque); testque->max_keys++; questatus = query_write(server_keylist, testque, node, &testque->max_keys, &numque); if(questatus == -1) { //printf("query incorrect\n"); } else if(questatus == 0) { //printf("query correct\n"); i = 1; if(server_keylist[i][0] == '\0') { printf("no matching keys detected.\n"); } while(server_keylist[i][0] != '\0'){ printf("keylist[%d]: %s\n", i, server_keylist[i]); i++; } if(i > testque->max_keys){ i = testque->max_keys; } encode_queryret(i, server_keylist, retline); //printf("query retline: %s\n", retline); sendall(sock, retline, sizeof(retline)); } free(testque); testque = NULL; } else{ //table doesn't exist printf("table doesn't exist\n"); cleanstring(retline); sprintf(retline, "&QUERY&$FAIL$^TABLE^"); sendall(sock, retline, sizeof(retline)); } puts("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%HANDLEQUERY_END%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); } sendall(sock, "\n", 1); return 0; }
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"); }
/* 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; }
static int write_subtitle_file_header(struct encoder_ctx *ctx, struct ccx_s_write *out) { int used; int ret = 0; switch (ctx->write_format) { case CCX_OF_SRT: // Subrip subtitles have no header ret = write_bom(ctx, out); if(ret < 0) return -1; break; case CCX_OF_WEBVTT: // WEBVTT subtitles have no header ret = write_bom(ctx, out); if(ret < 0) return -1; break; case CCX_OF_SAMI: // This header brought to you by McPoodle's CCASDI //fprintf_encoded (wb->fh, sami_header); ret = write_bom(ctx, out); if(ret < 0) return -1; REQUEST_BUFFER_CAPACITY(ctx,strlen (sami_header)*3); used = encode_line (ctx->buffer,(unsigned char *) sami_header); ret = write (out->fh, ctx->buffer,used); break; case CCX_OF_SMPTETT: // This header brought to you by McPoodle's CCASDI //fprintf_encoded (wb->fh, sami_header); ret = write_bom(ctx, out); if(ret < 0) return -1; REQUEST_BUFFER_CAPACITY(ctx,strlen (smptett_header)*3); used=encode_line (ctx->buffer,(unsigned char *) smptett_header); ret = write(out->fh, ctx->buffer, used); if(ret < used) { mprint("WARNING: Unable to write complete Buffer \n"); return -1; } break; case CCX_OF_RCWT: // Write header rcwt_header[7] = ctx->in_fileformat; // sets file format version if (ctx->send_to_srv) net_send_header(rcwt_header, sizeof(rcwt_header)); else { ret = write(out->fh, rcwt_header, sizeof(rcwt_header)); if(ret < 0) { mprint("Unable to write rcwt header\n"); return -1; } } break; case CCX_OF_RAW: ret = write(out->fh,BROADCAST_HEADER, sizeof(BROADCAST_HEADER)); if(ret < sizeof(BROADCAST_HEADER)) { mprint("Unable to write Raw header\n"); return -1; } case CCX_OF_SPUPNG: ret = write_bom(ctx, out); if(ret < 0) return -1; write_spumux_header(ctx, out); break; case CCX_OF_TRANSCRIPT: // No header. Fall thru ret = write_bom(ctx, out); if(ret < 0) return -1; default: break; } return ret; }
struct encoder_ctx *init_encoder(struct encoder_cfg *opt) { int ret; int i; struct encoder_ctx *ctx = malloc(sizeof(struct encoder_ctx)); if(!ctx) return NULL; ctx->buffer = (unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY); if (!ctx->buffer) { free(ctx); return NULL; } ctx->capacity=INITIAL_ENC_BUFFER_CAPACITY; ctx->srt_counter = 0; ctx->program_number = opt->program_number; ctx->send_to_srv = opt->send_to_srv; ctx->multiple_files = opt->multiple_files; ctx->first_input_file = opt->first_input_file; ret = init_output_ctx(ctx, opt); if (ret != EXIT_OK) { freep(&ctx->buffer); free(ctx); return NULL; } ctx->in_fileformat = opt->in_format; /** used in case of SUB_EOD_MARKER */ ctx->prev_start = -1; ctx->subs_delay = opt->subs_delay; ctx->last_displayed_subs_ms = 0; ctx->date_format = opt->date_format; ctx->millis_separator = opt->millis_separator; ctx->startcredits_displayed = 0; ctx->encoding = opt->encoding; ctx->write_format = opt->write_format; ctx->transcript_settings = &opt->transcript_settings; ctx->no_bom = opt->no_bom; ctx->sentence_cap = opt->sentence_cap; ctx->trim_subs = opt->trim_subs; ctx->autodash = opt->autodash; ctx->no_font_color = opt->no_font_color; ctx->no_type_setting = opt->no_type_setting; ctx->gui_mode_reports = opt->gui_mode_reports; ctx->extract = opt->extract; ctx->subline = (unsigned char *) malloc (SUBLINESIZE); if(!ctx->subline) { freep(&ctx->out); freep(&ctx->buffer); free(ctx); return NULL; } ctx->start_credits_text = opt->start_credits_text; ctx->end_credits_text = opt->end_credits_text; ctx->startcreditsnotbefore = opt->startcreditsnotbefore; ctx->startcreditsnotafter = opt->startcreditsnotafter; ctx->startcreditsforatleast = opt->startcreditsforatleast; ctx->startcreditsforatmost = opt->startcreditsforatmost; ctx->endcreditsforatleast = opt->endcreditsforatleast; ctx->endcreditsforatmost = opt->endcreditsforatmost; ctx->new_sentence = 1; // Capitalize next letter? if (opt->line_terminator_lf) ctx->encoded_crlf_length = encode_line(ctx, ctx->encoded_crlf, (unsigned char *) "\n"); else ctx->encoded_crlf_length = encode_line(ctx, ctx->encoded_crlf, (unsigned char *) "\r\n"); ctx->encoded_br_length = encode_line(ctx, ctx->encoded_br, (unsigned char *) "<br>"); for (i = 0; i < ctx->nb_out; i++) write_subtitle_file_header(ctx,ctx->out+i); ctx->dtvcc_extract = opt->dtvcc_extract; return ctx; }