diff --git a/src/608.c b/src/608.c index 2ea46a74..ec064e1e 100644 --- a/src/608.c +++ b/src/608.c @@ -251,7 +251,6 @@ void write_char(const unsigned char c, struct s_context_cc608 *context) context->ts_start_of_current_line = get_fts(); context->ts_last_char_received = get_fts(); } - } /* Handle MID-ROW CODES. */ @@ -1208,6 +1207,14 @@ void process608(const unsigned char *data, int length, struct s_context_cc608 *c // printf ("\r[%02X:%02X]\n",hi,lo); + if (hi>=0x10 && hi<=0x1e) { + int ch = (hi<=0x17)? 1 : 2; + if (current_field == 2) + ch+=2; + + file_report.cc_channels_608[ch - 1] = 1; + } + if (hi >= 0x01 && hi <= 0x0E && (context == NULL || context->my_field == 2)) // XDS can only exist in field 2. { if (context) @@ -1217,6 +1224,8 @@ void process608(const unsigned char *data, int length, struct s_context_cc608 *c ts_start_of_xds=get_fts(); in_xds_mode=1; } + + file_report.xds=1; } if (hi == 0x0F && in_xds_mode && (context == NULL || context->my_field == 2)) // End of XDS block { diff --git a/src/708.c b/src/708.c index 7dead176..2060cd7d 100644 --- a/src/708.c +++ b/src/708.c @@ -1142,8 +1142,12 @@ void process_current_packet (void) pos = current_packet+len; // Move to end break; } - if (service_number>0 && decoders[service_number-1].inited) - process_service_block (&decoders[service_number-1], pos, block_length); + + if (block_length != 0) + file_report.services708[service_number] = 1; + + if (service_number>0 && decoders[service_number-1].inited) + process_service_block (&decoders[service_number-1], pos, block_length); pos+=block_length; // Skip data } @@ -1168,7 +1172,7 @@ void do_708 (const unsigned char *data, int datalength) 1 byte for cc_valid 1 byte for cc_type 2 bytes for the actual data */ - if (!do_cea708) + if (!do_cea708 && !ccx_options.print_file_reports) return; for (int i=0;isentence_cap_file=NULL; // Extra words file? options->live_stream=0; // 0 -> A regular file options->messages_target=1; // 1=stdout + options->print_file_reports=0; /* Levenshtein's parameters, for string comparison */ options->levdistmincnt=2; // Means 2 fails or less is "the same"... options->levdistmaxpct=10; // ...10% or less is also "the same" diff --git a/src/ccextractor.h b/src/ccextractor.h index 93e0de35..efe49b64 100644 --- a/src/ccextractor.h +++ b/src/ccextractor.h @@ -42,6 +42,7 @@ struct ccx_s_options // Options from user parameters int nofontcolor; int notypesetting; struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process + int print_file_reports; /* subtitle codec type */ enum cxx_code_type codec; @@ -156,6 +157,22 @@ struct gop_time_code }; +/* Report information */ +#define SUB_STREAMS_CNT 10 +struct file_report_t +{ + unsigned program_cnt; + unsigned width; + unsigned height; + unsigned aspect_ratio; + unsigned frame_rate; + unsigned xds : 1; + unsigned cc_channels_608[4]; + unsigned services708[63]; + unsigned dvb_sub_pid[SUB_STREAMS_CNT]; + unsigned tlt_sub_pid[SUB_STREAMS_CNT]; +} file_report; + // Stuff for telcc.cpp struct ccx_s_teletext_config { @@ -306,6 +323,7 @@ int processmp4 (char *file); // params_dump.cpp void params_dump(void); +void print_file_report(void); // output.cpp void init_write (struct ccx_s_write *wb); @@ -583,6 +601,9 @@ extern int timestamps_on_transcript; extern unsigned teletext_mode; +#define MAX_TLT_PAGES 1000 +extern short int seen_sub_page[MAX_TLT_PAGES]; + extern uint64_t utc_refvalue; // UTC referential value extern struct ccx_s_teletext_config tlt_config; extern uint32_t tlt_packet_counter; diff --git a/src/es_functions.c b/src/es_functions.c index 72a0f3e7..7f63a1cd 100644 --- a/src/es_functions.c +++ b/src/es_functions.c @@ -398,6 +398,11 @@ static int sequence_header(struct bitstream *esstream) unsigned aspect_ratio = (unsigned) read_bits(esstream,4); unsigned frame_rate = (unsigned) read_bits(esstream,4); + file_report.width = hor_size; + file_report.height = vert_size; + file_report.aspect_ratio = aspect_ratio; + file_report.frame_rate = frame_rate; + // Discard some information read_bits(esstream, 18+1+10+1); diff --git a/src/file_functions.c b/src/file_functions.c index 57e87fd7..58f37ecd 100644 --- a/src/file_functions.c +++ b/src/file_functions.c @@ -177,6 +177,9 @@ int switch_to_next_file (LLONG bytesinbuffer) /* Close current and make sure things are still sane */ if (infd!=-1) { + if (ccx_options.print_file_reports) + print_file_report(); + close_input_file (); if (inputsize>0 && ((past+bytesinbuffer) < inputsize) && !processed_enough) { diff --git a/src/params.c b/src/params.c index fbbbe997..962f6308 100644 --- a/src/params.c +++ b/src/params.c @@ -272,6 +272,12 @@ void set_output_format (const char *format) ccx_options.date_format=ODF_HHMMSSMS; timestamps_on_transcript=1; } + else if (strcmp (format,"report")==0) + { + ccx_options.write_format=CCX_OF_NULL; + ccx_options.messages_target=0; + ccx_options.print_file_reports=1; + } else if (strcmp (format,"raw")==0) ccx_options.write_format=CCX_OF_RAW; else if (strcmp (format, "smptett")==0) @@ -396,11 +402,13 @@ void usage (void) mprint (" ttxt -> Timed Transcript (transcription with time\n"); mprint (" info)\n"); mprint (" smptett -> SMPTE Timed Text (W3C TTML) format.\n"); - mprint (" spupng -> Set of .xml and .png files for use with\n"); - mprint (" dvdauthor's spumux.\n"); - mprint (" See \"Notes on spupng output format\"\n"); - - mprint (" null -> Don't produce any file output\n\n"); + mprint (" spupng -> Set of .xml and .png files for use with\n"); + mprint (" dvdauthor's spumux.\n"); + mprint (" See \"Notes on spupng output format\"\n"); + mprint (" null -> Don't produce any file output\n"); + mprint (" report -> Prints to stdout information about captions"); + mprint (" in specified input. Don't produce any file"); + mprint (" output\n\n"); mprint (" Note: Teletext output can only be srt, txt or ttxt for now.\n\n"); mprint ("Options that affect how input files will be processed.\n"); @@ -578,7 +586,7 @@ void usage (void) mprint (" If codec type is not selected then first elementry stream suitable for \n" " subtitle is selected, please consider -teletext -noteletext override this\n" " option.\n" - " -cocdec dvbsub select the dvb subtitle from all elementry stream,\n" + " -codec dvbsub select the dvb subtitle from all elementry stream,\n" " if stream of dvb subtitle type is not found then \n" " nothing is selected and no subtitle is generated\n" " -nocodec dvbsub ignore dvb subtitle and follow default behaviour\n" diff --git a/src/params_dump.c b/src/params_dump.c index a4720df5..3b5bc838 100644 --- a/src/params_dump.c +++ b/src/params_dump.c @@ -200,3 +200,165 @@ void params_dump(void) } } + +void print_file_report(void) +{ + #define Y_N(cond) ((cond) ? "Yes" : "No") + + printf("File: "); + switch (ccx_options.input_source) + { + case CCX_DS_FILE: + printf("%s\n", inputfile[current_file]); + break; + case CCX_DS_STDIN: + printf("stdin\n"); + break; + case CCX_DS_NETWORK: + printf("network\n"); + break; + } + + printf("StreamMode: "); + switch (stream_mode) + { + case CCX_SM_TRANSPORT: + printf("transport_stream\n"); + + printf("ProgramCount: %d\n", file_report.program_cnt); + + printf("ProgramNumbers: "); + for (int i = 0; i < pmt_array_length; i++) + { + if (pmt_array[i].program_number == 0) + continue; + + printf("%u ", pmt_array[i].program_number); + } + printf("\n"); + + for (int i = 0; i < 65536; i++) + { + if (PIDs_programs[i] == 0) + continue; + + printf("PID: %u, Program: %u, ", i, PIDs_programs[i]->program_number); + int j; + for (j = 0; j < SUB_STREAMS_CNT; j++) + { + if (file_report.dvb_sub_pid[j] == i) + { + printf("DVB Subtitles\n"); + break; + } + if (file_report.tlt_sub_pid[j] == i) + { + printf("Teletext Subtitles\n"); + break; + } + } + if (j == SUB_STREAMS_CNT) + printf("%s\n", desc[PIDs_programs[i]->printable_stream_type]); + } + + break; + case CCX_SM_PROGRAM: + printf("program_stream\n"); + break; + case CCX_SM_ASF: + printf("ASF\n"); + break; + case CCX_SM_WTV: + printf("WTV\n"); + break; + case CCX_SM_ELEMENTARY_OR_NOT_FOUND: + printf("not_found\n"); + break; + } + + if (ccx_bufferdatatype == CCX_PES) + { + printf("Width: %u\n", file_report.width); + printf("Height: %u\n", file_report.height); + printf("AspectRatio: %s\n", aspect_ratio_types[file_report.aspect_ratio]); + printf("FrameRate: %s\n", framerates_types[file_report.frame_rate]); + } + + if (file_report.program_cnt > 1) + printf("//////// Program #%u: ////////\n", TS_program_number); + + printf("DVB-Subtitles: "); + int j; + for (j = 0; j < SUB_STREAMS_CNT; j++) + { + unsigned pid = file_report.dvb_sub_pid[j]; + if (pid == 0) + continue; + if (PIDs_programs[pid]->program_number == TS_program_number) + { + printf("Yes\n"); + break; + } + } + if (j == SUB_STREAMS_CNT) + printf("No\n"); + + printf("Teletext: "); + for (j = 0; j < SUB_STREAMS_CNT; j++) + { + unsigned pid = file_report.tlt_sub_pid[j]; + if (pid == 0) + continue; + if (PIDs_programs[pid]->program_number == TS_program_number) + { + printf("Yes\n"); + + printf("PagesWithSubtitles: "); + for (int i = 0; i < MAX_TLT_PAGES; i++) + { + if (seen_sub_page[i] == 0) + continue; + + printf("%d ", i); + } + printf("\n"); + break; + } + } + if (j == SUB_STREAMS_CNT) + printf("No\n"); + + printf("EIA-608: %s\n", Y_N(cc_stats[0] > 0 || cc_stats[1] > 0)); + + if (cc_stats[0] > 0 || cc_stats[1] > 0) + { + printf("XDSPresent: %s\n", Y_N(file_report.xds)); + + printf("CC1: %s\n", Y_N(file_report.cc_channels_608[0])); + printf("CC2: %s\n", Y_N(file_report.cc_channels_608[1])); + printf("CC3: %s\n", Y_N(file_report.cc_channels_608[2])); + printf("CC4: %s\n", Y_N(file_report.cc_channels_608[3])); + } + + printf("CEA-708: %s\n", Y_N(cc_stats[2] > 0 || cc_stats[3] > 0)); + + if (cc_stats[2] > 0 || cc_stats[3] > 0) + { + printf("Services: "); + for (int i = 0; i < 63; i++) + { + if (file_report.services708[i] == 0) + continue; + printf("%d ", i); + } + printf("\n"); + + printf("PrimaryLanguagePresent: %s\n", Y_N(file_report.services708[1])); + + printf("SecondaryLanguagePresent: %s\n", Y_N(file_report.services708[2])); + } + + memset(&file_report, 0, sizeof (struct file_report_t)); + + #undef Y_N +} diff --git a/src/telxcc.c b/src/telxcc.c index f6907ba0..a5d9cd07 100644 --- a/src/telxcc.c +++ b/src/telxcc.c @@ -121,7 +121,7 @@ static const char* TTXT_COLOURS[8] = { #define MAX_TLT_PAGES 1000 -static short int seen_sub_page[MAX_TLT_PAGES]; +short int seen_sub_page[MAX_TLT_PAGES]; // 1-byte alignment; just to be sure, this struct is being used for explicit type conversion // FIXME: remove explicit type conversion from buffer to structs diff --git a/src/ts_tables.c b/src/ts_tables.c index 515b720b..32ecf026 100644 --- a/src/ts_tables.c +++ b/src/ts_tables.c @@ -170,6 +170,65 @@ int parse_PMT (int pos) i += ES_info_length; } dbg_print(CCX_DMT_PMT, "---\n"); + + unsigned newcappid = 0; + unsigned newcap_stream_type = 0; + dbg_print(CCX_DMT_VERBOSE, "\nProgram map section (PMT)\n"); + + for (unsigned i=0; i < stream_data && (i+4) es_info; es_info += desc_len) + { + enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++); + desc_len = (*es_info++); + + if(descriptor_tag == CCX_MPEG_DSC_DVB_SUBTITLE) + { + int k = 0; + for (int j = 0; j < SUB_STREAMS_CNT; j++) { + if (file_report.dvb_sub_pid[i] == 0) + k = j; + if (file_report.dvb_sub_pid[i] == elementary_PID) + { + k = j; + break; + } + } + file_report.dvb_sub_pid[k] = elementary_PID; + } + if(IS_VALID_TELETEXT_DESC(descriptor_tag)) + { + int k = 0; + for (int j = 0; j < SUB_STREAMS_CNT; j++) { + if (file_report.tlt_sub_pid[i] == 0) + k = j; + if (file_report.tlt_sub_pid[i] == elementary_PID) + { + k = j; + break; + } + } + file_report.tlt_sub_pid[k] = elementary_PID; + } + } + i += ES_info_length; + } + if (TS_program_number || !ccx_options.ts_autoprogram) { if( payload.pid != pmtpid) @@ -188,10 +247,6 @@ int parse_PMT (int pos) } } - unsigned newcappid = 0; - unsigned newcap_stream_type = 0; - dbg_print(CCX_DMT_VERBOSE, "\nProgram map section (PMT)\n"); - for( unsigned i=0; i < stream_data && (i+4) es_info ;es_info += desc_len) { enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++); desc_len = (*es_info++); @@ -248,12 +303,12 @@ int parse_PMT (int pos) && ES_info_length && ccx_stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2) // MPEG-2 Packetized Elementary Stream packets containing private data { - unsigned char *es_info = payload_start + i + 5; - for (desc_len = 0;(payload_start + i + 5 + ES_info_length) - es_info ;es_info += desc_len) - { - enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++); - desc_len = (*es_info++); - if(!IS_VALID_TELETEXT_DESC(descriptor_tag)) + unsigned char *es_info = payload_start + i + 5; + for (desc_len = 0;(payload_start + i + 5 + ES_info_length) - es_info ;es_info += desc_len) + { + enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++); + desc_len = (*es_info++); + if(!IS_VALID_TELETEXT_DESC(descriptor_tag)) continue; telxcc_init(); if (!ccx_options.ts_forced_cappid) @@ -263,10 +318,11 @@ int parse_PMT (int pos) } ccx_options.teletext_mode =CCX_TXT_IN_USE; mprint ("VBI/teletext stream ID %u (0x%x) for SID %u (0x%x)\n", - elementary_PID, elementary_PID, program_number, program_number); - } + elementary_PID, elementary_PID, program_number, program_number); + } } + if (ccx_options.teletext_mode==CCX_TXT_FORBIDDEN && ccx_stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2) // MPEG-2 Packetized Elementary Stream packets containing private data { @@ -452,19 +508,17 @@ int parse_PAT (void) unsigned ts_prog_map_pid = 0; dbg_print(CCX_DMT_PAT, "\nProgram association section (PAT)\n"); - int temp=0; + file_report.program_cnt=0; for( unsigned i=0; i < programm_data; i+=4) { unsigned program_number = ((payload_start[i] << 8) | payload_start[i+1]); if( !program_number ) continue; - temp++; - if (temp>=2) // Found 2 programs, we don't need more - break; + file_report.program_cnt++; } - is_multiprogram = (temp>1); + is_multiprogram = (file_report.program_cnt>1); for( unsigned i=0; i < programm_data; i+=4) {