int parse_PMT (struct ccx_demuxer *ctx, unsigned char *buf, int len,  struct program_info *pinfo)
{
	int must_flush = 0;
	int ret = 0;
	unsigned char desc_len = 0;
	unsigned char *sbuf = buf;
	unsigned int olen = len;
	uint32_t crc;

	uint8_t table_id;
	uint16_t section_length;
	uint16_t program_number;
	uint8_t version_number;
	uint8_t current_next_indicator;
	uint8_t section_number;
	uint8_t last_section_number;

	uint16_t pi_length;

	crc = (*(int32_t*)(sbuf+olen-4));
	table_id = buf[0];

	/* TO-DO: We're currently parsing the PMT making assumptions that there's only one section with table_id=2,
	but that doesn't have to be the case. There's a sample (friends_tbs.ts) that shows a previous section with
	table_id = 0xc0. I can't find any place that says that 0xc0 (Program Information Table) must come before
	table_id = 2, so we should process sections in any order.
	Check https://github.com/CCExtractor/ccextractor/issues/385 for more info
	*/
	if (table_id == 0xC0)
	{
		/*
		 * Acc to System Information for Satellite Distribution
		 * of Digital Television for Cable and MMDS (ANSI/SCTE 57 2003 )
		 * PROGRAM INFORMATION Table found in PMT
		 */
		dbg_print(CCX_DMT_PARSE, "PMT: PROGRAM INFORMATION Table need implementation");
		// For now, just parse its length and remove it from the buffer
		unsigned c0length = (buf[1] << 8 | buf[2]) & 0xFFF; // 12 bytes
		dbg_print(CCX_DMT_PARSE, "Program information table length: %u", c0length);
		memmove(buf, buf + c0length + 3, len - c0length -3); // First 3 bytes are for the table_id and the length, don't count
		table_id = buf[0];
		// return 0;
	}
	else if (table_id == 0xC1)
	{
                //SCTE 57 2003
		dbg_print(CCX_DMT_PARSE, "PMT: PROGRAM NAME Table need implementation");
		unsigned c0length = (buf[1] << 8 | buf[2]) & 0xFFF; // 12 bytes
		dbg_print(CCX_DMT_PARSE, "Program name message length: %u", c0length);
		memmove(buf, buf + c0length + 3, len - c0length - 3); // First 3 bytes are for the table_id and the length, don't count
		table_id = buf[0];
		//return 0;
	}
	else if(table_id != 0x2)
	{
		mprint("Please Report: Unknown table id in PMT expected 0x02 found 0x%X\n", table_id);
		return 0;
	}

	section_length = (((buf[1] & 0x0F) << 8)| buf[2]);
	if(section_length > (len - 3))
	{
		return 0; //We don't have the full section yet. We will parse again when we have it.
	}

	program_number = ((buf[3] << 8)	| buf[4]);
	version_number = (buf[5] & 0x3E) >> 1;

	current_next_indicator = buf[5] & 0x01;
	// This table is not active, no need to evaluate
	if (!current_next_indicator)
		return 0;

	memcpy (pinfo->saved_section, buf, len);

	if (pinfo->analysed_PMT_once == CCX_TRUE && pinfo->version == version_number)
	{
		if (pinfo->version == version_number)
		{
			/* Same Version number and there was valid or similar CRC last time */
			if ( pinfo->valid_crc == CCX_TRUE || pinfo->crc == crc )
				return 0;

		}
		else if ( (pinfo->version+1)%32 != version_number)
			mprint("TS PMT:Glitch in version number incremnt");
	}
	pinfo->version = version_number;


	section_number = buf[6];
	last_section_number = buf[7];
	if ( last_section_number > 0 )
	{
		mprint("Long PMTs are not supported - skipped.\n");
		return 0;
	}

	pinfo->pcr_pid = (((buf[8] & 0x1F) << 8)
			| buf[9]);
	pi_length = (((buf[10] & 0x0F) << 8)
			| buf[11]);

	if( 12 + pi_length >  len )
	{
		// If we would support long PMTs, this would be wrong.
		mprint("program_info_length cannot be longer than the payload_length - skipped\n");
		return 0;
	}
	buf += 12 + pi_length;
	len -= (12 + pi_length);


	unsigned stream_data = section_length - 9 - pi_length - 4; // prev. bytes and CRC

	dbg_print(CCX_DMT_PARSE, "Read PMT packet  (id: %u) program number: %u\n",
			table_id, program_number);
	dbg_print(CCX_DMT_PARSE, "  section length: %u  number: %u  last: %u\n",
			section_length, section_number, last_section_number);
	dbg_print(CCX_DMT_PARSE, "  version_number: %u  current_next_indicator: %u\n",
			version_number, current_next_indicator);
	dbg_print(CCX_DMT_PARSE, "  PCR_PID: %u  data length: %u  payload_length: %u\n",
			pinfo->pcr_pid, stream_data, len);

	if (!pmt_warning_shown && stream_data+4 > len )
	{
		dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Probably parsing incomplete PMT, expected data longer than available payload.\n");
		pmt_warning_shown=1;
	}
	// Make a note of the program number for all PIDs, so we can report it later
	for( unsigned i=0; i < stream_data && (i+4)<len; i+=5)
	{
		enum ccx_stream_type stream_type = buf[i];
		unsigned elementary_PID = (((buf[i+1] & 0x1F) << 8)
				| buf[i+2]);
		unsigned ES_info_length = (((buf[i+3] & 0x0F) << 8)
				| buf[i+4]);
		if (ctx->PIDs_programs[elementary_PID]==NULL)
		{
			ctx->PIDs_programs[elementary_PID]=(struct PMT_entry *) malloc (sizeof (struct PMT_entry));
			if (ctx->PIDs_programs[elementary_PID]==NULL)
				fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory to process PMT.");
		}
		ctx->PIDs_programs[elementary_PID]->elementary_PID=elementary_PID;
		ctx->PIDs_programs[elementary_PID]->stream_type = stream_type;
		ctx->PIDs_programs[elementary_PID]->program_number=program_number;
		ctx->PIDs_programs[elementary_PID]->printable_stream_type=get_printable_stream_type (stream_type);
		dbg_print(CCX_DMT_PMT, "%6u | %3X (%3u) | %s\n",elementary_PID,stream_type,stream_type,
				desc[ctx->PIDs_programs[elementary_PID]->printable_stream_type]);
		process_ccx_mpeg_descriptor (buf+i+5,ES_info_length);
		i += ES_info_length;
	}
	dbg_print(CCX_DMT_PMT, "---\n");

	dbg_print(CCX_DMT_VERBOSE, "\nProgram map section (PMT)\n");

	for (unsigned i=0; i < stream_data && (i+4)<len; i+=5)
	{
		enum ccx_stream_type stream_type = buf[i];
		unsigned elementary_PID = (((buf[i+1] & 0x1F) << 8)
				| buf[i+2]);
		unsigned ES_info_length = (((buf[i+3] & 0x0F) << 8)
				| buf[i+4]);

		if (!ccx_options.print_file_reports ||
				stream_type != CCX_STREAM_TYPE_PRIVATE_MPEG2 ||
				!ES_info_length)
		{
			i += ES_info_length;
			continue;
		}

		unsigned char *es_info = buf + i + 5;
		for (desc_len = 0;(buf + 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(descriptor_tag == CCX_MPEG_DSC_DVB_SUBTITLE)
			{
				int k = 0;
				for (int j = 0; j < SUB_STREAMS_CNT; j++) {
					if (ctx->freport.dvb_sub_pid[j] == 0)
						k = j;
					if (ctx->freport.dvb_sub_pid[j] == elementary_PID)
					{
						k = j;
						break;
					}
				}
				ctx->freport.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 (ctx->freport.tlt_sub_pid[j] == 0)
						k = j;
					if (ctx->freport.tlt_sub_pid[j] == elementary_PID)
					{
						k = j;
						break;
					}
				}
				ctx->freport.tlt_sub_pid[k] = elementary_PID;
			}
		}
		i += ES_info_length;
	}

	for( unsigned i=0; i < stream_data && (i+4)<len; i+=5)
	{
		enum ccx_stream_type stream_type = buf[i];
		unsigned elementary_PID = (((buf[i+1] & 0x1F) << 8)
				| buf[i+2]);
		unsigned ES_info_length = (((buf[i+3] & 0x0F) << 8)
				| buf[i+4]);


		if(stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2 &&
				ES_info_length  )
		{
			unsigned char *es_info = buf + i + 5;
			for (desc_len = 0;(buf + i + 5 + ES_info_length) > es_info ;es_info += desc_len)
			{
				void *ptr;
				enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++);
				desc_len = (*es_info++);
				if(CCX_MPEG_DESC_DATA_COMP == descriptor_tag)
				{
					int16_t component_id = 0;
					if(!IS_FEASIBLE(ctx->codec, ctx->nocodec, CCX_CODEC_ISDB_CC))
						continue;
					if (desc_len < 2)
						break;

					component_id = RB16(es_info);
					if (component_id != 0x08)
						break;
					mprint ("*****ISDB subtitles detected\n");
					ptr = init_isdb_decoder();
					if (ptr == NULL)
						break;
					update_capinfo(ctx, elementary_PID, stream_type, CCX_CODEC_ISDB_CC, program_number, ptr);

				}
				if(CCX_MPEG_DSC_DVB_SUBTITLE == descriptor_tag)
				{
					struct dvb_config cnf;
#ifndef ENABLE_OCR
					if(ccx_options.write_format != CCX_OF_SPUPNG)
					{
						mprint ("DVB subtitles detected, OCR subsystem not present. Use -out=spupng for graphic output\n");
						continue;
					}
#endif
					if (!IS_FEASIBLE(ctx->codec, ctx->nocodec, CCX_CODEC_DVB))
						continue;

					memset((void*)&cnf,0,sizeof(struct dvb_config));
					ret = parse_dvb_description(&cnf,es_info,desc_len);
					if(ret < 0)
						break;
					ptr = dvbsub_init_decoder(&cnf);
					if (ptr == NULL)
						break;
					update_capinfo(ctx, elementary_PID, stream_type, CCX_CODEC_DVB, program_number, ptr);
					max_dif = 30;
				}
			}
		}
		else if(stream_type == CCX_STREAM_TYPE_PRIVATE_USER_MPEG2 && ES_info_length  )
		{
			//if this any generally used video stream tyoe get clashed with ATSC/SCTE standard
			//then this code can go in some atsc flag
			unsigned char *es_info = buf + i + 5;
			for (desc_len = 0;(buf + i + 5 + ES_info_length) > es_info ;es_info += desc_len)
			{
				enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++);
				int nb_service;
				int is_608;
				int ser_i;
				desc_len = (*es_info++);
				if (CCX_MPEG_DSC_CAPTION_SERVICE == descriptor_tag)
				{
					nb_service = es_info[0] & 0x1f;
					for (ser_i = 0; ser_i < nb_service; ser_i++)
					{
						dbg_print(CCX_DMT_PMT, "CC SERVICE %d: language (%c%c%c)", nb_service,
							es_info[1], es_info[2], es_info[3]);
						is_608 = es_info[4] >> 7;
						dbg_print(CCX_DMT_PMT, "%s", is_608?" CEA-608":" CEA-708");
						dbg_print(CCX_DMT_PMT, "%s", is_608?" CEA-608":" CEA-708");
					}
				}
				update_capinfo(ctx, elementary_PID, stream_type, CCX_CODEC_ATSC_CC, program_number, NULL);
			}
		}
Exemple #2
0
int parse_PMT (struct lib_ccx_ctx *ctx, unsigned char *buf, int len, int pos)
{
	int must_flush=0;
	int ret = 0;
	unsigned char desc_len = 0;

	if ((ccx_options.ts_forced_cappid || (ccx_options.teletext_mode==CCX_TXT_IN_USE && ccx_options.ts_cappid)) &&
		cap_stream_type!=CCX_STREAM_TYPE_UNKNOWNSTREAM) // Already know what we need, skip
		return 0;

	/* We keep a copy of all PMTs, even if not interesting to us for now */
	if (pmt_array[pos].last_pmt_payload!=NULL && len == pmt_array[pos].last_pmt_length &&
		!memcmp (buf, pmt_array[pos].last_pmt_payload, len))
	{
		// dbg_print(CCX_DMT_PMT, "PMT hasn't changed, skipping.\n");
		return 0;
	}
	pmt_array[pos].last_pmt_payload=(unsigned char *)
	realloc (pmt_array[pos].last_pmt_payload, len+8); // Extra 8 in case memcpy copies dwords, etc
	if (pmt_array[pos].last_pmt_payload==NULL)
		fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory to process PMT.\n");
	memcpy (pmt_array[pos].last_pmt_payload, buf, len);
	pmt_array[pos].last_pmt_length = len;


    unsigned table_id = buf[0];
    unsigned section_length = (((buf[1] & 0x0F) << 8)
                               | buf[2]);
    unsigned program_number = ((buf[3] << 8)
                               | buf[4]);

    unsigned version_number = (buf[5] & 0x3E) >> 1;
    unsigned current_next_indicator = buf[5] & 0x01;
    if (!current_next_indicator)
        // This table is not active, no need to evaluate
        return 0;
    unsigned section_number = buf[6];
    unsigned last_section_number = buf[7];
    if ( last_section_number > 0 )
    {
        mprint("Long PMTs are not supported - skipped.\n");
        return 0;
    }
    unsigned PCR_PID = (((buf[8] & 0x1F) << 8)
                        | buf[9]);
    unsigned pi_length = (((buf[10] & 0x0F) << 8)
                          | buf[11]);

    if( 12 + pi_length >  len )
    {
        // If we would support long PMTs, this would be wrong.
        mprint("program_info_length cannot be longer than the payload_length - skipped\n");
        return 0;
    }
    buf += 12 + pi_length;
    len = tspacket+188-buf;

    unsigned stream_data = section_length - 9 - pi_length - 4; // prev. bytes and CRC

    dbg_print(CCX_DMT_PARSE, "Read PMT packet  (id: %u) program number: %u\n",
           table_id, program_number);
    dbg_print(CCX_DMT_PARSE, "  section length: %u  number: %u  last: %u\n",
           section_length, section_number, last_section_number);
    dbg_print(CCX_DMT_PARSE, "  version_number: %u  current_next_indicator: %u\n",
           version_number, current_next_indicator);
    dbg_print(CCX_DMT_PARSE, "  PCR_PID: %u  data length: %u  payload_length: %u\n",
           PCR_PID, stream_data, len);

    if (!pmt_warning_shown && stream_data+4 > len )
    {
		dbg_print (CCX_DMT_GENERIC_NOTICES, "\rWarning: Probably parsing incomplete PMT, expected data longer than available payload.\n");
		pmt_warning_shown=1;
    }
	dbg_print(CCX_DMT_PMT, "\nProgram Map Table for program %u, PMT PID: %u\n",
		program_number,payload.pid);
	// Make a note of the program number for all PIDs, so we can report it later
    for( unsigned i=0; i < stream_data && (i+4)<len; i+=5)
    {
        unsigned ccx_stream_type = buf[i];
        unsigned elementary_PID = (((buf[i+1] & 0x1F) << 8)
                                   | buf[i+2]);
        unsigned ES_info_length = (((buf[i+3] & 0x0F) << 8)
                                   | buf[i+4]);
		if (ctx->PIDs_programs[elementary_PID]==NULL)
		{
			ctx->PIDs_programs[elementary_PID]=(struct PMT_entry *) malloc (sizeof (struct PMT_entry));
			if (ctx->PIDs_programs[elementary_PID]==NULL)
				fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory to process PMT.");
		}
		ctx->PIDs_programs[elementary_PID]->elementary_PID=elementary_PID;
		ctx->PIDs_programs[elementary_PID]->ccx_stream_type=ccx_stream_type;
		ctx->PIDs_programs[elementary_PID]->program_number=program_number;
		ctx->PIDs_programs[elementary_PID]->PMT_PID=payload.pid;
		ctx->PIDs_programs[elementary_PID]->printable_stream_type=get_printable_stream_type (ccx_stream_type);
		dbg_print(CCX_DMT_PMT, "%6u | %3X (%3u) | %s\n",elementary_PID,ccx_stream_type,ccx_stream_type,
			desc[ctx->PIDs_programs[elementary_PID]->printable_stream_type]);
		process_ccx_mpeg_descriptor (buf+i+5,ES_info_length);
        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)<len; i+=5)
    {
		unsigned ccx_stream_type = buf[i];
		unsigned elementary_PID = (((buf[i+1] & 0x1F) << 8)
                                   | buf[i+2]);
		unsigned ES_info_length = (((buf[i+3] & 0x0F) << 8)
                                   | buf[i+4]);

		if (!ccx_options.print_file_reports ||
			ccx_stream_type != CCX_STREAM_TYPE_PRIVATE_MPEG2 ||
			!ES_info_length)
		{
			i += ES_info_length;
			continue;
		}

		unsigned char *es_info = buf + i + 5;
		for (desc_len = 0;(buf + 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(descriptor_tag == CCX_MPEG_DSC_DVB_SUBTITLE)
			{
				int k = 0;
				for (int j = 0; j < SUB_STREAMS_CNT; j++) {
					if (ctx->freport.dvb_sub_pid[i] == 0)
						k = j;
					if (ctx->freport.dvb_sub_pid[i] == elementary_PID)
					{
						k = j;
						break;
					}
				}
				ctx->freport.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 (ctx->freport.tlt_sub_pid[i] == 0)
						k = j;
					if (ctx->freport.tlt_sub_pid[i] == elementary_PID)
					{
						k = j;
						break;
					}
				}
				ctx->freport.tlt_sub_pid[k] = elementary_PID;
			}
		}
		i += ES_info_length;
	}

	if (TS_program_number || !ccx_options.ts_autoprogram)
	{
		if( payload.pid != pmtpid)
		{
			// This isn't the PMT we are interested in (note: If TS_program_number=0 &&
			// autoprogram then we need to check this PMT in case there's a suitable
			// stream)
			return 0;
		}
		if (program_number != TS_program_number) // Is this the PMT of the program we want?
		{
			// Only use PMTs with matching program number
			dbg_print(CCX_DMT_PARSE,"Reject this PMT packet (pid: %u) program number: %u\n",
					   pmtpid, program_number);
			return 0;
		}
	}

    for( unsigned i=0; i < stream_data && (i+4)<len; i+=5)
    {
		unsigned ccx_stream_type = buf[i];
		unsigned elementary_PID = (((buf[i+1] & 0x1F) << 8)
                                   | buf[i+2]);
		unsigned ES_info_length = (((buf[i+3] & 0x0F) << 8)
                                   | buf[i+4]);

		/* There is no information about elementry stream */
		/*if(!ES_info_length)
			continue; */

		if (ccx_options.ts_cappid==0 && ccx_stream_type==ccx_options.ts_datastreamtype) // Found a stream with the type the user wants
		{
			ccx_options.ts_forced_cappid=1;
			ccx_options.ts_cappid = newcappid = elementary_PID;
			cap_stream_type=CCX_STREAM_TYPE_UNKNOWNSTREAM;
		}
		if(IS_FEASIBLE(ccx_options.codec,ccx_options.nocodec,CCX_CODEC_DVB) &&
				!ccx_options.ts_cappid &&
				ccx_stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2 &&
				ES_info_length  )
		{
			unsigned char *es_info = buf + i + 5;
			for (desc_len = 0;(buf + 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++);
#ifndef ENABLE_OCR
				if(ccx_options.write_format != CCX_OF_SPUPNG )
				{
					mprint ("DVB subtitles detected, OCR subsystem not present. Use -out=spupng for graphic output\n");
					continue;
				}
#endif
				if(CCX_MPEG_DSC_DVB_SUBTITLE == descriptor_tag)
				{
					struct dvb_config cnf;
					memset((void*)&cnf,0,sizeof(struct dvb_config));
					ret = parse_dvb_description(&cnf,es_info,desc_len);
					if(ret < 0)
						break;
					ccx_dvb_context = dvbsub_init_decoder(&cnf);
					if (ccx_dvb_context == NULL)
						break;
					ccx_options.ts_cappid = newcappid = elementary_PID;
					cap_stream_type = newcap_stream_type = ccx_stream_type;
					max_dif = 30;
				}
			}
		}

		if (IS_FEASIBLE(ccx_options.codec,ccx_options.nocodec,CCX_CODEC_TELETEXT) && (ccx_options.teletext_mode==CCX_TXT_AUTO_NOT_YET_FOUND ||
			(ccx_options.teletext_mode==CCX_TXT_IN_USE && !ccx_options.ts_cappid)) // Want teletext but don't know the PID yet
			&& ES_info_length
			&& ccx_stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2) // MPEG-2 Packetized Elementary Stream packets containing private data
		{
			unsigned char *es_info = buf + i + 5;
			for (desc_len = 0;(buf + 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(ctx);
				if (!ccx_options.ts_forced_cappid)
				{
					ccx_options.ts_cappid = newcappid = elementary_PID;
					cap_stream_type = newcap_stream_type = ccx_stream_type;
				}
				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);
			}

		}

		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
		{
			unsigned descriptor_tag = buf[i + 5];
			if (descriptor_tag == 0x45)
			{
				ccx_options.ts_cappid = newcappid = elementary_PID;
				cap_stream_type = newcap_stream_type = ccx_stream_type;
				mprint ("VBI stream ID %u (0x%x) for SID %u (0x%x) - teletext is disabled, will be processed as closed captions.\n",
					elementary_PID, elementary_PID, program_number, program_number);
			}
		}

		if (ccx_options.ts_forced_cappid && elementary_PID==ccx_options.ts_cappid && cap_stream_type==CCX_STREAM_TYPE_UNKNOWNSTREAM)
		{
			// We found the user selected CAPPID in PMT. We make a note of its type and don't
			// touch anything else
			if (ccx_stream_type>=0x80 && ccx_stream_type<=0xFF)
			{
				if (ccx_options.ts_forced_streamtype==CCX_STREAM_TYPE_UNKNOWNSTREAM)
				{
					mprint ("I can't tell the stream type of the manually selected PID.\n");
					mprint ("Please pass -streamtype to select manually.\n");
					fatal (EXIT_FAILURE, "(user assistance needed)");
				}
				else
					cap_stream_type = newcap_stream_type = ccx_options.ts_forced_streamtype;
			}
			else
				cap_stream_type = newcap_stream_type = ccx_stream_type;
			continue;
		}

		if ((ccx_stream_type==CCX_STREAM_TYPE_VIDEO_H264 || ccx_stream_type==CCX_STREAM_TYPE_VIDEO_MPEG2)
			&& ccx_options.teletext_mode != CCX_TXT_IN_USE)
		{
			newcappid = elementary_PID;
			newcap_stream_type = ccx_stream_type;
		}

        // For the print command below
        unsigned tmp_stream_type = get_printable_stream_type (ccx_stream_type);
        dbg_print(CCX_DMT_VERBOSE, "  %s stream [0x%02x]  -  PID: %u\n",
                desc[tmp_stream_type],
                ccx_stream_type, elementary_PID);
        i += ES_info_length;
    }
    if (!newcappid && !ccx_options.ts_forced_cappid)
    {
		if (!ccx_options.ts_autoprogram)
		{
			mprint("No supported stream with caption data found, won't be able to process\n");
			mprint("unless a PID is provided manually or packet inspection is enabled.\n");
		}
		else
		{
			mprint("No supported stream with caption data found in this program.\n");
		}
		return 0;
    }
    if (newcappid != ccx_options.ts_cappid && !ccx_options.ts_forced_cappid)
    {
        ccx_options.ts_cappid = newcappid;
        cap_stream_type = newcap_stream_type;
        mprint ("Decode captions from program %d - %s stream [0x%02x]  -  PID: %u\n",
                program_number , desc[cap_stream_type], cap_stream_type, ccx_options.ts_cappid);
		if (ccx_options.ts_autoprogram) // Make our program selection official
		{
			pmtpid=payload.pid;
			TS_program_number = program_number;
		}
        // If we have data flush it
        if( ctx->capbuflen > 0 )
            must_flush=1;
    }
	return must_flush;
}