⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) ENST 2000-200X *					All rights reserved * *  This file is part of GPAC / mp42ts application * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include <gpac/media_tools.h>#include <gpac/constants.h>#include <gpac/ietf.h>#include "mp42ts.h"void usage() {	fprintf(stderr, "usage: mp42ts [options] dst\n"					"With options being: \n"					"-prog=FILE     specifies an input file used for a TS service\n"					"                * currently only supports ISO files and SDP files\n"					"                * option can be used several times, once for each program\n"					"-rate=R        specifies target rate in kbits/sec of the multiplex\n"					"                If not set, transport stream will be of variable bitrate\n"					"\n"					"dst can be a file, an RTP or a UDP destination (unicast/multicast)\n"		);}static GFINLINE void m2ts_dump_time(M2TS_Time *time, char *name){	fprintf(stdout, "%s: %d%03d\n", name, time->sec, time->nanosec/1000000);}static GFINLINE Bool m2ts_time_less(M2TS_Time *a, M2TS_Time *b) {	if (a->sec>b->sec) return 0;	if (a->sec==b->sec) return (a->nanosec<b->nanosec) ? 1 : 0;	return 1;}static GFINLINE Bool m2ts_time_less_or_equal(M2TS_Time *a, M2TS_Time *b) {	if (a->sec>b->sec) return 0;	if (a->sec==b->sec) return (a->nanosec>b->nanosec) ? 0 : 1;	return 1;}static GFINLINE void m2ts_time_inc(M2TS_Time *time, u32 delta_inc_num, u32 delta_inc_den){	u64 n_sec;	u32 sec;	/*couldn't compute bitrate - we need to have more info*/	if (!delta_inc_den) return;	sec = delta_inc_num / delta_inc_den;	if (sec) {		time->sec += sec;		sec *= delta_inc_den;		delta_inc_num = delta_inc_num % sec;	}	/*move to nanosec - 0x3B9ACA00 = 1000*1000*1000 */	n_sec = delta_inc_num;	n_sec *= 0x3B9ACA00;	n_sec /= delta_inc_den;	time->nanosec += (u32) n_sec;	while (time->nanosec >= 0x3B9ACA00) {		time->nanosec -= 0x3B9ACA00;		time->sec ++;	}}/************************************ * Section-related functions  ************************************/void m2ts_mux_table_update(M2TS_Mux_Stream *stream, u8 table_id, u16 table_id_extension,						   u8 *table_payload, u32 table_payload_length, 						   Bool use_syntax_indicator, Bool private_indicator,						   Bool use_checksum) {	u32 overhead_size;	u32 offset;	u32 section_number, nb_sections;	M2TS_Mux_Table *table, *prev_table;	u32 maxSectionLength;	M2TS_Mux_Section *section, *prev_sec;	GF_BitStream *bs;	/* check if there is already a table with that id */	prev_table = NULL;	table = stream->tables;	while (table) {		if (table->table_id == table_id) {			/* if yes, we need to flush the table and increase the version number */			M2TS_Mux_Section *sec = table->section;			while (sec) {				M2TS_Mux_Section *sec2 = sec->next;				free(sec->data);				free(sec);				sec = sec2;			}			table->version_number = (table->version_number + 1)%0x1F;			break;		}		prev_table = table;		table = table->next;	}	if (!table) {		/* if no, the table is created */		GF_SAFEALLOC(table, M2TS_Mux_Table);		table->table_id = table_id;		if (prev_table) prev_table->next = table;		else stream->tables = table;	}	if (!table_payload_length) return;	switch (table_id) {	case GF_M2TS_TABLE_ID_PMT:	case GF_M2TS_TABLE_ID_PAT:	case GF_M2TS_TABLE_ID_SDT_ACTUAL:	case GF_M2TS_TABLE_ID_SDT_OTHER:	case GF_M2TS_TABLE_ID_BAT:		maxSectionLength = 1024; 		break;	case GF_M2TS_TABLE_ID_MPEG4_BIFS:	case GF_M2TS_TABLE_ID_MPEG4_OD:		maxSectionLength = 4096; 		break;	default:		fprintf(stderr, "Cannot create sections for table with id %d\n", table_id);		return;	}	overhead_size = SECTION_HEADER_LENGTH;	if (use_syntax_indicator) overhead_size += SECTION_ADDITIONAL_HEADER_LENGTH + CRC_LENGTH;		section_number = 0;	nb_sections = 1;	while (nb_sections*(maxSectionLength - overhead_size)<table_payload_length) nb_sections++; 	switch (table_id) {	case GF_M2TS_TABLE_ID_PMT:		if (nb_sections > 1)			fprintf(stdout,"Warning: last section number for PMT shall be 0 !!\n");		break;	default:		break;	}		prev_sec = NULL;	offset = 0;	while (offset < table_payload_length) {		u32 remain;		GF_SAFEALLOC(section, M2TS_Mux_Section);		remain = table_payload_length - offset;		if (remain > maxSectionLength - overhead_size) {			section->length = maxSectionLength;		} else {			section->length = remain + overhead_size;		}		bs = gf_bs_new(NULL,0,GF_BITSTREAM_WRITE);		/* first header (not included in section length */		gf_bs_write_int(bs,	table_id, 8);		gf_bs_write_int(bs,	use_syntax_indicator, 1);		gf_bs_write_int(bs,	private_indicator, 1); 		gf_bs_write_int(bs,	3, 2);  /* reserved bits are all set */		gf_bs_write_int(bs,	section->length - SECTION_HEADER_LENGTH, 12);			if (use_syntax_indicator) {			/* second header */			gf_bs_write_int(bs,	table_id_extension, 16);			gf_bs_write_int(bs,	3, 2); /* reserved bits are all set */			gf_bs_write_int(bs,	table->version_number, 5);			gf_bs_write_int(bs,	1, 1); /* current_next_indicator = 1: we don't send version in advance */			gf_bs_write_int(bs,	section_number, 8);			section_number++;			gf_bs_write_int(bs,	nb_sections-1, 8);		}		gf_bs_write_data(bs, table_payload + offset, section->length - overhead_size);		offset += section->length - overhead_size;			if (use_syntax_indicator) {			/* place holder for CRC */			gf_bs_write_u32(bs, 0);		}		gf_bs_get_content(bs, (char**) &section->data, &section->length); 		gf_bs_del(bs);		if (use_syntax_indicator) {			u32 CRC;			CRC = gf_m2ts_crc32(section->data,section->length-CRC_LENGTH); 			section->data[section->length-4] = (CRC >> 24) & 0xFF;			section->data[section->length-3] = (CRC >> 16) & 0xFF;			section->data[section->length-2] = (CRC >> 8) & 0xFF;			section->data[section->length-1] = CRC & 0xFF;		}			if (prev_sec) prev_sec->next = section;		else table->section = section;		prev_sec = section;	}	stream->current_table = stream->tables;	stream->current_section = stream->current_table->section;	stream->current_section_offset = 0;}void m2ts_mux_table_update_bitrate(M2TS_Mux *mux, M2TS_Mux_Stream *stream){	M2TS_Mux_Table *table;		/*update PMT*/	if (stream->table_needs_update) 		stream->process(mux, stream);	stream->bit_rate = 0;	table = stream->tables;	while (table) {		M2TS_Mux_Section *section = table->section;		while (section) {			stream->bit_rate += section->length;			section = section->next;		}		table = table->next;	}	stream->bit_rate *= 8;	if (!stream->refresh_rate_ms) stream->refresh_rate_ms = 500;	stream->bit_rate *= 1000;	stream->bit_rate /= stream->refresh_rate_ms;}/* length of adaptation_field_length; */ #define ADAPTATION_LENGTH_LENGTH 1/* discontinuty flag, random access flag ... */#define ADAPTATION_FLAGS_LENGTH 1 /* length of encoded pcr */#define PCR_LENGTH 6static u32 m2ts_add_adaptation(GF_BitStream *bs, 				   Bool has_pcr, u64 time, 				   Bool is_rap, 				   u32 padding_length){	u32 adaptation_length;	adaptation_length = ADAPTATION_FLAGS_LENGTH + (has_pcr?PCR_LENGTH:0) + padding_length;	gf_bs_write_int(bs,	adaptation_length, 8);	gf_bs_write_int(bs,	0, 1);			// discontinuity indicator	gf_bs_write_int(bs,	is_rap, 1);		// random access indicator	gf_bs_write_int(bs,	0, 1);			// es priority indicator	gf_bs_write_int(bs,	has_pcr, 1);	// PCR_flag 	gf_bs_write_int(bs,	0, 1);			// OPCR flag	gf_bs_write_int(bs,	0, 1);			// splicing point flag	gf_bs_write_int(bs,	0, 1);			// transport private data flag	gf_bs_write_int(bs,	0, 1);			// adaptation field extension flag	if (has_pcr) {		u64 PCR_base, PCR_ext;		PCR_base = time;		gf_bs_write_long_int(bs, PCR_base, 33); 		gf_bs_write_int(bs,	0, 6); // reserved		PCR_ext = 0;		gf_bs_write_long_int(bs, PCR_ext, 9);	}	while (padding_length) {		gf_bs_write_u8(bs,	0xff); // stuffing byte		padding_length--;	}	return adaptation_length + ADAPTATION_LENGTH_LENGTH;}void m2ts_mux_table_get_next_packet(M2TS_Mux_Stream *stream, u8 *packet){	GF_BitStream *bs;	M2TS_Mux_Table *table;	M2TS_Mux_Section *section;	u32 payload_length, padding_length;	u8 adaptation_field_control;	table = stream->current_table;	assert(table);	section = stream->current_section;	assert(section);	bs = gf_bs_new(packet, 188, GF_BITSTREAM_WRITE);		gf_bs_write_int(bs,	0x47, 8); // sync	gf_bs_write_int(bs,	0, 1);    // error indicator	if (stream->current_section_offset == 0) {		gf_bs_write_int(bs,	1, 1);    // payload start indicator	} else {		/* No section concatenation yet!!!*/		gf_bs_write_int(bs,	0, 1);    // payload start indicator	}	if (!stream->current_section_offset) payload_length = 183;	else payload_length = 184;	if (section->length - stream->current_section_offset >= payload_length) {		padding_length = 0;		adaptation_field_control = M2TS_ADAPTATION_NONE;	} else {				/* in all the following cases, we write an adaptation field */		adaptation_field_control = M2TS_ADAPTATION_AND_PAYLOAD;		/* we need at least 2 bytes for adaptation field headers (no pcr) */		payload_length -= 2;		if (section->length - stream->current_section_offset >= payload_length) {			padding_length = 0;		} else {			padding_length = payload_length - section->length - stream->current_section_offset; 			payload_length -= padding_length;		}	}	assert(payload_length + stream->current_section_offset <= section->length);		gf_bs_write_int(bs,	0, 1);    // priority indicator	gf_bs_write_int(bs,	stream->pid, 13); // section pid	gf_bs_write_int(bs,	0, 2);    // scrambling indicator	gf_bs_write_int(bs,	adaptation_field_control, 2);    // we do not use adaptation field for sections 	gf_bs_write_int(bs,	stream->continuity_counter, 4);   // continuity counter	if (stream->continuity_counter < 15) stream->continuity_counter++;	else stream->continuity_counter=0;	if (adaptation_field_control != M2TS_ADAPTATION_NONE)		m2ts_add_adaptation(bs, 0, 0, 0, padding_length);	if (!stream->current_section_offset) { //write pointer field		gf_bs_write_u8(bs, 0); /* no concatenations of sections in ts packets, so start address is 0 */	}	gf_bs_del(bs);	memcpy(packet+188-payload_length, section->data + stream->current_section_offset, payload_length);	stream->current_section_offset += payload_length;		//m2ts_time_inc(stream->time, 1504/*188*8*/, muxer->bit_rate);	if (stream->current_section_offset == section->length) {		stream->current_section_offset = 0;		stream->current_section = stream->current_section->next;		if (!stream->current_section) {			stream->current_table = stream->current_table->next;			if (!stream->current_table) {				stream->current_table = stream->tables;				/*update time*/				m2ts_time_inc(&stream->time, stream->refresh_rate_ms, 1000);			}			stream->current_section = stream->current_table->section;		}	}}Bool m2ts_stream_process_pat(M2TS_Mux *muxer, M2TS_Mux_Stream *stream){	if (stream->table_needs_update) { /* generate table payload */		M2TS_Mux_Program *prog;		GF_BitStream *bs;		u8 *payload;		u32 size;		bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);		prog = muxer->programs;		while (prog) {			gf_bs_write_u16(bs, prog->number);			gf_bs_write_int(bs, 0x7, 3);	/*reserved*/			gf_bs_write_int(bs, prog->pmt->pid, 13);	/*reserved*/			prog = prog->next;		}		gf_bs_get_content(bs, (char**)&payload, &size);		gf_bs_del(bs);		m2ts_mux_table_update(stream, GF_M2TS_TABLE_ID_PAT, muxer->ts_id, payload, size, 1, 0, 0);		stream->table_needs_update = 0;		free(payload);	}	return 1;}Bool m2ts_stream_process_pmt(M2TS_Mux *muxer, M2TS_Mux_Stream *stream){	if (stream->table_needs_update) { /* generate table payload */		M2TS_Mux_Stream *es;		u8 *payload;		u32 length;		GF_BitStream *bs;		bs = gf_bs_new(NULL,0,GF_BITSTREAM_WRITE);		gf_bs_write_int(bs,	0x7, 3); // reserved		gf_bs_write_int(bs,	stream->program->pcr->pid, 13);		gf_bs_write_int(bs,	0xF, 4); // reserved			if (1 /* !iod */) {			gf_bs_write_int(bs,	0, 12); // program info length =0		} else {#if 0			u32 len;			len = iod->length + 4;			gf_bs_write_int(bs,	len, 12); // program info length = iod len			/*for (i =0; i< gf_list_count(program->desc); i++)			{				// program descriptors				// IOD			}*/			gf_bs_write_int(bs,	29, 8); // tag			len = iod->length + 2;			gf_bs_write_int(bs,	len, 8); // length			gf_bs_write_int(bs,	2, 8);  // Scope_of_IOD_label : 0x10 iod unique a l'int閞ieur de programme													// 0x11 iod unoque dans la flux ts			gf_bs_write_int(bs,	2, 8);  // IOD_label			gf_bs_write_data(bs, iod->data, iod->length);  // IOD#endif		}			es = stream->program->streams;		while (es) {			gf_bs_write_int(bs,	es->mpeg2_stream_type, 8);			gf_bs_write_int(bs,	0x7, 3); // reserved			gf_bs_write_int(bs,	es->pid, 13);			gf_bs_write_int(bs,	0xF, 4); // reserved						/* Second Loop Descriptor */			if (0 /*iod*/) {#if 0				gf_bs_write_int(bs,	4, 12); // ES info length = 4 :only SL Descriptor				gf_bs_write_int(bs,	30, 8); // tag				gf_bs_write_int(bs,	1, 8); // length				gf_bs_write_int(bs,	es->mpeg4_es_id, 16);  // mpeg4_esid#endif			} else {				gf_bs_write_int(bs,	0, 12);			}			es = es->next;		}			gf_bs_get_content(bs, (char**)&payload, &length);		gf_bs_del(bs);		m2ts_mux_table_update(stream, GF_M2TS_TABLE_ID_PMT, stream->program->number, payload, length, 1, 0, 0);		stream->table_needs_update = 0;		free(payload);	}	return 1;}Bool m2ts_stream_process_stream(M2TS_Mux *muxer, M2TS_Mux_Stream *stream){	if (stream->pck_offset == stream->pck.data_len) {		if (stream->ifce->caps & GF_ESI_AU_PULL_CAP) {			if (stream->pck_offset) stream->ifce->input_ctrl(stream->ifce, GF_ESI_INPUT_DATA_RELEASE, NULL);			stream->pck_offset = 0;			stream->pck.data_len = 0;			/*EOF*/			if (stream->ifce->caps & GF_ESI_STREAM_IS_OVER) return 0;			stream->ifce->input_ctrl(stream->ifce, GF_ESI_INPUT_DATA_PULL, &stream->pck);		} else {			M2TS_Packet *pck;			/*flush input pipe*/			stream->ifce->input_ctrl(stream->ifce, GF_ESI_INPUT_DATA_FLUSH, NULL);			gf_mx_p(stream->mx);			/*discard first packet*/			if (stream->pck_offset) {				assert(stream->pck_first);				pck = stream->pck_first;				stream->pck_first = pck->next;				free(pck->data);				free(pck);			}			stream->pck_offset = 0;			stream->pck.data_len = 0;			/*fill pck*/			pck = stream->pck_first;			if (!pck) {				gf_mx_v(stream->mx);				return 0;			}			stream->pck.cts = pck->cts;			stream->pck.data = pck->data;			stream->pck.data_len = pck->data_len;			stream->pck.dts = pck->dts;			stream->pck.flags = pck->flags;			gf_mx_v(stream->mx);		}		/*!! watchout !!*/		if (stream->ts_scale) {			stream->pck.cts = (u64) (stream->ts_scale * (s64) stream->pck.cts);			stream->pck.dts = (u64) (stream->ts_scale * (s64) stream->pck.dts);		}		/*initializing the PCR*/		if (!stream->program->pcr_init) {			if (stream==stream->program->pcr) {				stream->program->pcr_init_ts_time = muxer->time;				stream->program->pcr_init_time = stream->pck.dts;				stream->program->pcr_init = 1;			} else {				/*don't send until PCR is initialized*/				return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -