[Ffmpeg-devel] mpeg transport streams

Marcus Hunger marcus.hunger
Wed Jun 1 11:10:09 CEST 2005


--- ../FFMpeg-20050530/libavformat/mpegtsenc.c	2005-03-09 03:12:44.000000000 +0100
+++ libavformat/mpegtsenc.c	2005-06-01 10:55:59.000000000 +0200
@@ -22,6 +22,8 @@
 
 /* write DVB SI sections */
 
+char *service_name = 0;
+
 static const uint32_t crc_table[256] = {
 	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
 	0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
@@ -82,12 +84,12 @@ unsigned int mpegts_crc32(const uint8_t 
 /*********************************************/
 /* mpegts section writer */
 
-typedef struct MpegTSSection {
-    int pid;
-    int cc;
-    void (*write_packet)(struct MpegTSSection *s, const uint8_t *packet);
-    void *opaque;
-} MpegTSSection;
+//typedef struct MpegTSSection {
+//    int pid;
+//    int cc;
+//    void (*write_packet)(struct MpegTSSection *s, const uint8_t *packet);
+//    void *opaque;
+//} MpegTSSection;
 
 /* NOTE: 4 bytes must be left at the end for the crc32 */
 void mpegts_write_section(MpegTSSection *s, uint8_t *buf, int len)
@@ -186,40 +188,210 @@ int mpegts_write_section1(MpegTSSection 
 /* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
 #define DEFAULT_PES_HEADER_FREQ 16
 #define DEFAULT_PES_PAYLOAD_SIZE ((DEFAULT_PES_HEADER_FREQ - 1) * 184 + 170)
+#define MAX_PES_PAYLOAD_SIZE DEFAULT_PES_PAYLOAD_SIZE * 1024
 
 /* we retransmit the SI info at this rate */
 #define SDT_RETRANS_TIME 500
 #define PAT_RETRANS_TIME 100
+#define CAT_RETRANS_TIME 500
 
 typedef struct MpegTSWriteStream {
     int pid; /* stream associated pid */
     int cc;
+    int discontinuity_indicator;
     int payload_index;
     int64_t payload_pts;
-    uint8_t payload[DEFAULT_PES_PAYLOAD_SIZE];
+    uint8_t payload[MAX_PES_PAYLOAD_SIZE];
 } MpegTSWriteStream;
 
-typedef struct MpegTSService {
-    MpegTSSection pmt; /* MPEG2 pmt table context */
-    int pcr_pid;
-    int sid;           /* service ID */
-    char *name;
-    char *provider_name;
-} MpegTSService;
+
+//typedef struct MpegTSService {
+//    MpegTSSection pmt; /* MPEG2 pmt table context */
+//    int pcr_pid;
+//    int sid;           /* service ID */
+//    char *name;
+//    char *provider_name;
+//} MpegTSService;
 
 typedef struct MpegTSWrite {
     MpegTSSection pat; /* MPEG2 pat table */
     MpegTSSection sdt; /* MPEG2 sdt table context */
+    MpegTSSection cat; /* MPEG2 cat */
     MpegTSService **services;
     int sdt_packet_count;
     int sdt_packet_freq;
     int pat_packet_count;
     int pat_packet_freq;
+    int cat_packet_count;
+    int cat_packet_freq;
     int nb_services;
     int onid;
     int tsid;
+    int64_t bytes_written;
+    int64_t last_pcrbase;
+    int last_pcrext;
+    int needed_stuffing_packets;
+    int need_pcr;
+    int byte_rate;
 } MpegTSWrite;
 
+void mpegts_put_flush_packet(AVFormatContext * s)
+{
+    MpegTSWrite *tsctx;
+
+    tsctx = s->priv_data;
+
+    tsctx->bytes_written += (s->pb.buf_ptr - s->pb.buffer);
+
+    put_flush_packet(&s->pb);
+}
+
+void mpegts_write_stuffing_packets(AVFormatContext * s, unsigned int nb)
+{
+    uint8_t null_packet[TS_PACKET_SIZE];
+
+    memset(null_packet, 0xff, TS_PACKET_SIZE);
+
+    null_packet[0] = 0x47;	// sync
+    null_packet[1] = 0x1f;	// pid = 0x1fff; -> null_packet, no flags
+
+    null_packet[2] = 0xff;
+    null_packet[3] = 0x10;	// payload_present = 1
+    for (nb; nb > 0; nb--) {
+	put_buffer(&s->pb, null_packet, TS_PACKET_SIZE);
+	mpegts_put_flush_packet(s);
+    }
+}
+
+/*
+ * writes an adaption_field
+ * if need_pcr != 0, a pcr field is written 
+ *
+ */
+static void mpegts_write_adapt(int64_t pcrbase, int pcrext, uint8_t * q,
+			       int len, int need_pcr,
+			       int discontinuity_indicator)
+{
+    uint8_t outbyte;
+    int i;
+    char *stuffing = "stuffing";
+    int plen = strlen(stuffing);
+
+    if (len == 0)
+	return;
+
+    len--;
+
+    *q++ = len;
+
+    if (need_pcr != 0) {
+
+	*q++ = discontinuity_indicator << 7 | 1 << 4;	// discontinuity_indicator | pcr_flag
+
+	outbyte = 0;
+	for (i = 0; i < 48; i++) {
+	    outbyte <<= 1;
+	    if (i < 33) {
+		outbyte |= ((pcrbase >> (32 - i)) & 1);
+	    } else if (i >= 33 && i < 39) {
+		outbyte |= 0;	// reserved
+	    } else {
+		outbyte |= ((pcrext >> (47 - i)) & 1);	// ext
+	    }
+	    if ((i + 1) % 8 == 0) {
+		*q++ = outbyte;
+		outbyte = 0;
+	    }
+	}
+	len -= 7;
+    } else if (len > 0) {
+	*q++ = discontinuity_indicator << 7;
+	len -= 1;
+    }
+
+    for (i = 0; i < len; i++) {
+	*q++ = stuffing[i % plen];
+    }
+}
+
+static void mpegts_write_pcr(AVFormatContext * s, int64_t pcrbase,
+			     int pcrext, MpegTSWriteStream * ts_st)
+{
+    uint8_t pcr_packet[TS_PACKET_SIZE];
+
+    pcr_packet[0] = 0x47;
+    pcr_packet[1] = ts_st->pid >> 8;
+    pcr_packet[2] = ts_st->pid;
+    pcr_packet[3] = 1 << 5 | ((ts_st->cc - 1) & 0xf);
+    mpegts_write_adapt(pcrbase, pcrext, pcr_packet + 4, 184, 1,
+		       ts_st->discontinuity_indicator);
+    pcr_packet[5] |= ts_st->discontinuity_indicator << 7;
+    put_buffer(&s->pb, pcr_packet, TS_PACKET_SIZE);
+    mpegts_put_flush_packet(s);
+
+    ts_st->discontinuity_indicator = 0;
+}
+
+void calc_pcr(MpegTSWrite * ts, int64_t * pcrbase, int *pcrext)
+{
+    int64_t pcr;
+
+    pcr = ts->last_pcrbase * 300 + ts->last_pcrext;
+    pcr += 90000 * 300.0 * ts->bytes_written / ts->byte_rate;
+
+    *pcrbase = (int64_t) pcr / 300;
+    *pcrext = pcr % 300;
+}
+
+
+void mpegts_check_bitrate_underrun(AVFormatContext * s, int64_t ptsbase,
+				   MpegTSWriteStream * ts_st)
+{
+    MpegTSWrite *tsctx = s->priv_data;
+    int64_t missing_bytes;
+    int64_t expected_bytes;
+    int64_t lately_written, written = 0, t_written;
+    int first_loop = 1;
+    int64_t pcr;
+    int64_t pcrbase;
+    int pcrext;
+
+
+    expected_bytes =
+	(tsctx->byte_rate *
+	 ((ptsbase * 300) -
+	  (tsctx->last_pcrbase * 300 +
+	   tsctx->last_pcrext))) / (90000 * 300);
+
+    missing_bytes = expected_bytes - tsctx->bytes_written;
+    if (missing_bytes >= 0) {
+
+	int to_write;
+
+	while (missing_bytes > TS_PACKET_SIZE) {
+
+	    calc_pcr(tsctx, &pcrbase, &pcrext);
+	    if ((pcrbase - tsctx->last_pcrbase) / 90 > 23) {
+		tsctx->bytes_written = 0;
+		tsctx->last_pcrbase = pcrbase;
+		tsctx->last_pcrext = pcrext;
+		mpegts_write_pcr(s, tsctx->last_pcrbase,
+				 tsctx->last_pcrext, ts_st);
+
+	    } else {
+		mpegts_write_stuffing_packets(s, 1);
+	    }
+
+	    missing_bytes -= TS_PACKET_SIZE;
+
+	}
+
+    } else {
+	av_log(s, AV_LOG_INFO, "byterate overrun!!!!!\n");
+    }
+}
+
+
 static void mpegts_write_pat(AVFormatContext *s)
 {
     MpegTSWrite *ts = s->priv_data;
@@ -237,6 +409,25 @@ static void mpegts_write_pat(AVFormatCon
                           data, q - data);
 }
 
+
+/* write empty cat */
+static void mpegts_write_cat(AVFormatContext *s)
+{
+    uint8_t data[TS_PACKET_SIZE];
+    uint16_t len = 9;
+    MpegTSWrite *ts = s->priv_data;
+
+    data[0] = CAT_TID;
+    data[1] = 0xb0 | len >> 8;
+    data[2] = len & 0xff;
+    data[3] = 0;		// reserved
+    data[4] = 0;		// reserved
+    data[5] = 1;		// reserved | version | current_next_indicator
+    data[6] = 0;		// section_number
+    data[7] = 0;		// last_section_number
+    mpegts_write_section(&ts->cat, data, len + 3);
+}
+
 static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
 {
     //    MpegTSWrite *ts = s->priv_data;
@@ -386,11 +577,20 @@ static int mpegts_write_header(AVFormatC
     AVStream *st;
     int i, total_bit_rate;
 
+    ts->bytes_written = 0;
+    ts->last_pcrbase = 0;
+    ts->last_pcrext = 0;
+    ts->byte_rate = s->mux_rate;
+
     ts->tsid = DEFAULT_TSID;
     ts->onid = DEFAULT_ONID;
     /* allocate a single DVB service */
+
+    if (service_name == NULL) {
+	service_name = DEFAULT_SERVICE_NAME;
+    }
     service = mpegts_add_service(ts, DEFAULT_SID, 
-                                 DEFAULT_PROVIDER_NAME, DEFAULT_SERVICE_NAME);
+				 DEFAULT_PROVIDER_NAME, service_name);
     service->pmt.write_packet = section_write_packet;
     service->pmt.opaque = s;
 
@@ -404,6 +604,11 @@ static int mpegts_write_header(AVFormatC
     ts->sdt.write_packet = section_write_packet;
     ts->sdt.opaque = s;
 
+    ts->cat.pid = CAT_PID;
+    ts->cat.cc = 0;
+    ts->cat.write_packet = section_write_packet;
+    ts->cat.opaque = s;
+
     /* assign pids to each stream */
     total_bit_rate = 0;
     for(i = 0;i < s->nb_streams; i++) {
@@ -414,6 +619,7 @@ static int mpegts_write_header(AVFormatC
         st->priv_data = ts_st;
         ts_st->pid = DEFAULT_START_PID + i;
         ts_st->payload_pts = AV_NOPTS_VALUE;
+        ts_st->discontinuity_indicator = 1;
         /* update PCR pid if needed */
         if (st->codec.codec_type == CODEC_TYPE_VIDEO && 
             service->pcr_pid == 0x1fff)
@@ -426,6 +632,8 @@ static int mpegts_write_header(AVFormatC
         (TS_PACKET_SIZE * 8 * 1000);
     ts->pat_packet_freq = (total_bit_rate * PAT_RETRANS_TIME) / 
         (TS_PACKET_SIZE * 8 * 1000);
+    ts->cat_packet_freq = (total_bit_rate * CAT_RETRANS_TIME) / 
+        (TS_PACKET_SIZE * 8 * 1000);
 #if 0
     printf("%d %d %d\n", 
            total_bit_rate, ts->sdt_packet_freq, ts->pat_packet_freq);
@@ -435,10 +643,11 @@ static int mpegts_write_header(AVFormatC
        find them */
     mpegts_write_sdt(s);
     mpegts_write_pat(s);
+    mpegts_write_cat(s);
     for(i = 0; i < ts->nb_services; i++) {
         mpegts_write_pmt(s, ts->services[i]);
     }
-    put_flush_packet(&s->pb);
+    mpegts_put_flush_packet(s);
 
     return 0;
 
@@ -467,113 +676,239 @@ static void retransmit_si_info(AVFormatC
             mpegts_write_pmt(s, ts->services[i]);
         }
     }
+    if (++ts->cat_packet_count == ts->cat_packet_freq) {
+	ts->cat_packet_count = 0;
+	mpegts_write_cat(s);
+    }
+    mpegts_put_flush_packet(s);
 }
 
+
+struct ts_field {
+    uint8_t buf[TS_PACKET_SIZE];
+    int len;
+};
+
 /* NOTE: pes_data contains all the PES packet */
 static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
                              const uint8_t *payload, int payload_size,
                              int64_t pts)
 {
     MpegTSWriteStream *ts_st = st->priv_data;
+    MpegTSWrite *ts = s->priv_data;
     uint8_t buf[TS_PACKET_SIZE];
-    uint8_t *q;
+    uint8_t tbuf[TS_PACKET_SIZE];
+    uint8_t *q, *tq;
     int val, is_start, len, ts_len, header_len;
+    int64_t pcrbase;
+    int pcrext;
+    int adapt_len = 0;
+    int stuffing = 0;
+    int peshead_len;
+    int writepcr = 0;
+    enum { sync_flags_pid = 0, tsc_adapt_cc = 1, adapt = 2, pes =
+	    3 } ts_idx;
+
+    struct ts_field fields[4];
 
     is_start = 1;
+
+    calc_pcr(ts, &pcrbase, &pcrext);
+
+    if (ts->need_pcr && (pcrbase < pts)) {
+	mpegts_check_bitrate_underrun(s, pts, ts_st);
+    }
+
     while (payload_size > 0) {
-        retransmit_si_info(s);
 
-        /* prepare packet header */
-        q = buf;
-        *q++ = 0x47;
-        val = (ts_st->pid >> 8);
-        if (is_start)
-            val |= 0x40;
-        *q++ = val;
-        *q++ = ts_st->pid;
-        *q++ = 0x10 | ts_st->cc;
-        ts_st->cc = (ts_st->cc + 1) & 0xf;
-        if (is_start) {
-            /* write PES header */
-            *q++ = 0x00;
-            *q++ = 0x00;
-            *q++ = 0x01;
-            if (st->codec.codec_type == CODEC_TYPE_VIDEO)
-                *q++ = 0xe0;
-            else
-                *q++ = 0xc0;
-            if (pts != AV_NOPTS_VALUE)
-                header_len = 8;
-            else
-                header_len = 3;
-            len = payload_size + header_len;
-            *q++ = len >> 8;
-            *q++ = len;
-            *q++ = 0x80;
-            if (pts != AV_NOPTS_VALUE) {
-                *q++ = 0x80; /* PTS only */
-                *q++ = 0x05; /* header len */
-                val = (0x02 << 4) | 
-                    (((pts >> 30) & 0x07) << 1) | 1;
-                *q++ = val;
-                val = (((pts >> 15) & 0x7fff) << 1) | 1;
-                *q++ = val >> 8;
-                *q++ = val;
-                val = (((pts) & 0x7fff) << 1) | 1;
-                *q++ = val >> 8;
-                *q++ = val;
-            } else {
-                *q++ = 0x00;
-                *q++ = 0x00;
-            }
-            is_start = 0;
-        }
-        /* write header */
-        ts_len = q - buf;
-        put_buffer(&s->pb, buf, ts_len);
-        /* write data */
-        len = TS_PACKET_SIZE - ts_len;
-        if (len > payload_size)
-            len = payload_size;
-        put_buffer(&s->pb, payload, len);
-        payload += len;
-        payload_size -= len;
-        ts_len += len;
-        /* stuffing */
-        len = TS_PACKET_SIZE - ts_len;
-        if (len > 0) {
-            memset(buf, 0xff, len);
-            put_buffer(&s->pb, buf, len);
-        }
+
+	calc_pcr(ts, &pcrbase, &pcrext);
+
+	if (pts + 50000 < pcrbase) {
+	    av_log
+		(s, AV_LOG_ERROR, "pts < pcrbase %lld < %lld: codec_type: %s\n",
+		 pts + 50000, pcrbase, st->codec.codec_type ==
+		   CODEC_TYPE_VIDEO ? "video" : "audio");
+		   
+	}
+
+	retransmit_si_info(s);
+
+	fields[sync_flags_pid].len = fields[tsc_adapt_cc].len =
+	    fields[adapt].len = fields[pes].len = 0;
+
+	/* prepare packet header */
+	q = fields[sync_flags_pid].buf;
+	*q++ = 0x47;
+	val = (ts_st->pid >> 8);
+	if (is_start)
+	    val |= 0x40;
+	*q++ = val;
+	*q++ = ts_st->pid;
+	fields[sync_flags_pid].len = 3;
+
+	fields[tsc_adapt_cc].len = 1;
+
+	if (ts->need_pcr) {
+	    calc_pcr(ts, &pcrbase, &pcrext);
+	    if ((pcrbase - ts->last_pcrbase) / 90 > 23
+		|| ts_st->discontinuity_indicator == 1) {
+		ts->bytes_written = 0;
+		ts->last_pcrbase = pcrbase;
+		ts->last_pcrext = pcrext;
+		writepcr = 1;
+	    } else {
+		writepcr = 0;
+	    }
+	}
+
+	if (writepcr == 1) {
+	    fields[adapt].len = 8;
+	} else if (ts_st->discontinuity_indicator == 1) {
+	    fields[adapt].len = 2;
+	} else {
+	    fields[adapt].len = 0;
+	}
+
+	q = fields[pes].buf;
+	if (is_start) {
+	    pts += 50000;
+
+	    /* write PES header */
+
+	    *q++ = 0x00;
+	    *q++ = 0x00;
+	    *q++ = 0x01;
+	    if (st->codec.codec_type == CODEC_TYPE_VIDEO)
+		*q++ = 0xe0;
+	    else
+		*q++ = 0xc0;
+	    if (pts != AV_NOPTS_VALUE)
+		header_len = 8;
+	    else
+		header_len = 3;
+	    len = payload_size + header_len;
+	    if (st->codec.codec_type == CODEC_TYPE_VIDEO
+		&& DEFAULT_PES_HEADER_FREQ > 16) {
+		*q++ = 0;
+		*q++ = 0;
+	    } else {
+		*q++ = len >> 8;
+		*q++ = len;
+	    }
+	    *q++ = 0x80;
+	    if (pts != AV_NOPTS_VALUE) {
+		*q++ = 0x80;	/* PTS only */
+		*q++ = 0x05;	/* header len */
+		val = (0x02 << 4) | (((pts >> 30) & 0x07) << 1) | 1;
+		*q++ = val;
+		val = (((pts >> 15) & 0x7fff) << 1) | 1;
+		*q++ = val >> 8;
+		*q++ = val;
+		val = (((pts) & 0x7fff) << 1) | 1;
+		*q++ = val >> 8;
+		*q++ = val;
+	    } else {
+		*q++ = 0x00;
+		*q++ = 0x00;
+	    }
+	    is_start = 0;
+	}
+
+	/* write header */
+	peshead_len = q - fields[pes].buf;
+
+
+	/* write data */
+	len =
+	    TS_PACKET_SIZE - (fields[sync_flags_pid].len +
+			      fields[tsc_adapt_cc].len +
+			      fields[adapt].len + peshead_len);
+	if (len > payload_size)
+	    len = payload_size;
+	memcpy(fields[pes].buf + peshead_len, payload, len);
+	fields[pes].len = len + peshead_len;
+
+	payload += len;
+	payload_size -= len;
+	/* stuffing */
+	len =
+	    TS_PACKET_SIZE - (fields[sync_flags_pid].len +
+			      fields[tsc_adapt_cc].len +
+			      fields[adapt].len + fields[pes].len);
+	fields[adapt].len += len;
+
+	if (writepcr == 1 || fields[adapt].len > 0) {
+	    mpegts_write_adapt(pcrbase, pcrext, fields[adapt].buf,
+			       fields[adapt].len, writepcr,
+			       ts_st->discontinuity_indicator);
+	    ts_st->discontinuity_indicator = 0;
+	}
+	
+	q = fields[tsc_adapt_cc].buf;
+	if (fields[adapt].len > 0) {
+	    *q++ = 0x30 | ts_st->cc;	// write adaption_field
+	} else {
+	    *q++ = 0x10 | ts_st->cc;
+	}
+	ts_st->cc = (ts_st->cc + 1) & 0xf;
+
+	put_buffer(&s->pb, fields[sync_flags_pid].buf,
+		   fields[sync_flags_pid].len);
+	put_buffer(&s->pb, fields[tsc_adapt_cc].buf,
+		   fields[tsc_adapt_cc].len);
+	put_buffer(&s->pb, fields[adapt].buf, fields[adapt].len);
+	put_buffer(&s->pb, fields[pes].buf, fields[pes].len);
+	mpegts_put_flush_packet(s);
+
     }
-    put_flush_packet(&s->pb);
 }
 
+
 static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     AVStream *st = s->streams[pkt->stream_index];
     int size= pkt->size;
     uint8_t *buf= pkt->data;
     MpegTSWriteStream *ts_st = st->priv_data;
+    MpegTSWrite *ts = s->priv_data;
     int len;
+    int pes_payload_size;
+
+
+    if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
+	pes_payload_size = MAX_PES_PAYLOAD_SIZE;
+	ts->need_pcr = 1;
+    } else {
+	pes_payload_size = DEFAULT_PES_PAYLOAD_SIZE;
+	ts->need_pcr = 0;
+    }
 
     while (size > 0) {
-        len = DEFAULT_PES_PAYLOAD_SIZE - ts_st->payload_index;
+        len = pes_payload_size - ts_st->payload_index;
         if (len > size)
             len = size;
         memcpy(ts_st->payload + ts_st->payload_index, buf, len);
         buf += len;
         size -= len;
         ts_st->payload_index += len;
+        
         if (ts_st->payload_pts == AV_NOPTS_VALUE)
             ts_st->payload_pts = pkt->pts;
-        if (ts_st->payload_index >= DEFAULT_PES_PAYLOAD_SIZE) {
+        
+        if (ts_st->payload_index >= pes_payload_size) {
             mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index,
                              ts_st->payload_pts);
             ts_st->payload_pts = AV_NOPTS_VALUE;
             ts_st->payload_index = 0;
         }
     }
+    if (ts_st->payload_index > 0) {
+	mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index,
+			 ts_st->payload_pts);
+	ts_st->payload_pts = AV_NOPTS_VALUE;
+	ts_st->payload_index = 0;
+    }
     return 0;
 }
 
-------------- next part --------------
--- ../../FFMpeg-20050530/libavformat/mpegts.c	2005-05-26 22:17:11.000000000 +0200
+++ mpegts.c	2005-06-01 11:24:32.000000000 +0200
@@ -16,6 +16,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <string.h>
 #include "avformat.h"
 
 #include "mpegts.h"
@@ -23,94 +24,6 @@
 //#define DEBUG_SI
 //#define DEBUG_SEEK
 
-/* 1.0 second at 24Mbit/s */
-#define MAX_SCAN_PACKETS 32000
-
-/* maximum size in which we look for synchronisation if
-   synchronisation is lost */
-#define MAX_RESYNC_SIZE 4096
-
-static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type);
-
-enum MpegTSFilterType {
-    MPEGTS_PES,
-    MPEGTS_SECTION,
-};
-
-typedef void PESCallback(void *opaque, const uint8_t *buf, int len, int is_start);
-
-typedef struct MpegTSPESFilter {
-    PESCallback *pes_cb;
-    void *opaque;
-} MpegTSPESFilter;
-
-typedef void SectionCallback(void *opaque, const uint8_t *buf, int len);
-
-typedef void SetServiceCallback(void *opaque, int ret);
-
-typedef struct MpegTSSectionFilter {
-    int section_index;
-    int section_h_size;
-    uint8_t *section_buf;
-    int check_crc:1;
-    int end_of_section_reached:1;
-    SectionCallback *section_cb;
-    void *opaque;
-} MpegTSSectionFilter;
-
-typedef struct MpegTSFilter {
-    int pid;
-    int last_cc; /* last cc code (-1 if first packet) */
-    enum MpegTSFilterType type;
-    union {
-        MpegTSPESFilter pes_filter;
-        MpegTSSectionFilter section_filter;
-    } u;
-} MpegTSFilter;
-
-typedef struct MpegTSService {
-    int running:1;
-    int sid;
-    char *provider_name;
-    char *name;
-} MpegTSService;
-
-struct MpegTSContext {
-    /* user data */
-    AVFormatContext *stream;
-    int raw_packet_size; /* raw packet size, including FEC if present */
-    int auto_guess; /* if true, all pids are analized to find streams */
-    int set_service_ret;
-
-    int mpeg2ts_raw;  /* force raw MPEG2 transport stream output, if possible */
-    int mpeg2ts_compute_pcr; /* compute exact PCR for each transport stream packet */
-
-    /* used to estimate the exact PCR */
-    int64_t cur_pcr;
-    int pcr_incr;
-    int pcr_pid;
-    
-    /* data needed to handle file based ts */
-    int stop_parse; /* stop parsing loop */
-    AVPacket *pkt; /* packet containing av data */
-
-    /******************************************/
-    /* private mpegts data */
-    /* scan context */
-    MpegTSFilter *sdt_filter;
-    int nb_services;
-    MpegTSService **services;
-    
-    /* set service context (XXX: allocated it ?) */
-    SetServiceCallback *set_service_cb;
-    void *set_service_opaque;
-    MpegTSFilter *pat_filter;
-    MpegTSFilter *pmt_filter;
-    int req_sid;
-
-    MpegTSFilter *pids[NB_PID_MAX];
-};
-
 static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,
                                const uint8_t *buf, int buf_size, int is_start)
 {
@@ -148,6 +61,12 @@ static void write_section_data(AVFormatC
     }
 }
 
+/**
+ * allocates memory and assigns a SectionCallback-function to a PID
+ *
+ */
+
+
 MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int pid, 
                                          SectionCallback *section_cb, void *opaque,
                                          int check_crc)
@@ -180,6 +99,11 @@ MpegTSFilter *mpegts_open_section_filter
     return filter;
 }
 
+/**
+ * allocates memory und assigns a PESCallback-function  to a PID
+ *
+ */
+
 MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid, 
                                      PESCallback *pes_cb,
                                      void *opaque)
@@ -315,6 +239,19 @@ static char *getstr8(const uint8_t **pp,
     return str;
 }
 
+/**
+ * writes table_id (8bit), transport_stream_id (16bit), version_number (5bit),
+ * section_number (8bit) and last_section_number (8bit) to a SectionHeader
+ *
+ * this function works at least for 'program association section', 'ca section'
+ * and 'ts program map section'
+ *
+ * ISO/IEC 13818-1:2000(E) Annex F
+ *
+ */
+
+ 
+
 static int parse_section_header(SectionHeader *h, 
                                 const uint8_t **pp, const uint8_t *p_end)
 {
@@ -364,6 +301,14 @@ static MpegTSService *new_service(MpegTS
     return service;
 }
 
+/**
+ * parses a PMT-Section-Header. the read PCR_PID is set for the complete ts.
+ * XXX: is this correct? yes, here it is because we are not extracting more than one program
+ * pmt_cb is registered for a PMT_PID and gets called as soon as the pmt is received. it
+ * extracts all (?) PES-streams with a known codec and removes itself from the filterlist.
+ *
+ */
+
 static void pmt_cb(void *opaque, const uint8_t *section, int section_len)
 {
     MpegTSContext *ts = opaque;
@@ -385,6 +330,7 @@ static void pmt_cb(void *opaque, const u
     if (h->tid != PMT_TID || (ts->req_sid >= 0 && h->id != ts->req_sid) )
         return;
 
+/** die pcr_pid gibt den Strom von Paketen an, der die Zeitreferenz zum aktuellen Programm enthaelt */
     pcr_pid = get16(&p, p_end) & 0x1fff;
     if (pcr_pid < 0)
         return;
@@ -1136,23 +1082,45 @@ static int mpegts_read_header(AVFormatCo
 		s->ctx_flags |= AVFMTCTX_NOHEADER;
 		goto do_pcr;
 	    }
-            
-            /* tune to first service found */
-            for(i=0; i<ts->nb_services && ts->set_service_ret; i++){
-                service = ts->services[i];
-                sid = service->sid;
-#ifdef DEBUG_SI
-                printf("tuning to '%s'\n", service->name);
-#endif
-            
-                /* now find the info for the first service if we found any,
-                otherwise try to filter all PATs */
-                
-                url_fseek(pb, pos, SEEK_SET);
-                mpegts_set_service(ts, sid, set_service_cb, ts);
-                
-                handle_packets(ts, MAX_SCAN_PACKETS);
-            }
+
+
+	    if (ap && ap->selected_service[0] != 0) {
+		    char *name;
+		    // versuche ausgew?hlten Service zu selektieren
+		    for (i=0; i<ts->nb_services; i++) {
+			    name = ts->services[i]->name;
+			    if (name[0] < 0xc) name++;
+			    
+			    if (strcmp(ap->selected_service, name) == 0) {
+				sid = ts->services[i]->sid;
+				url_fseek(pb, pos, SEEK_SET);
+				mpegts_set_service(ts, sid, set_service_cb, ts);
+
+				handle_packets(ts, MAX_SCAN_PACKETS);
+				break;
+			    }
+		    }
+
+	    } else {
+		    /* tune to first service found */
+		    /* beim versuch noch einen service auszuwaehlen gibts nen segv */
+
+
+		    
+		    for(i=0; i<ts->nb_services && ts->set_service_ret; i++){
+			service = ts->services[i];
+			sid = service->sid;
+		    
+			/* now find the info for the first service if we found any,
+			otherwise try to filter all PATs */
+			
+			url_fseek(pb, pos, SEEK_SET);
+			mpegts_set_service(ts, sid, set_service_cb, ts);
+
+			handle_packets(ts, MAX_SCAN_PACKETS);
+		    }
+	    }
+	    
             /* if could not find service, exit */
             
             if (ts->set_service_ret != 0)
-------------- next part --------------
--- ../FFMpeg-20050530/libavformat/mpegts.h	2004-07-14 03:32:14.000000000 +0200
+++ libavformat/mpegts.h	2005-05-20 16:13:44.000000000 +0200
@@ -25,9 +25,11 @@
 /* pids */
 #define PAT_PID                 0x0000
 #define SDT_PID                 0x0011
+#define CAT_PID                 0x0001
 
 /* table ids */
 #define PAT_TID   0x00
+#define CAT_TID   0x01
 #define PMT_TID   0x02 
 #define SDT_TID   0x42
 
@@ -44,10 +46,115 @@
 #define STREAM_TYPE_AUDIO_AC3       0x81
 #define STREAM_TYPE_AUDIO_DTS       0x8a
 
+/** 
+ * 1.0 second at 24Mbit/s
+ * FIXME: the dvb-standard defines a maximum-interval for sdt of 2 seconds
+ */
+#define MAX_SCAN_PACKETS 32000
+
+/* maximum size in which we look for synchronisation if
+   synchronisation is lost */
+#define MAX_RESYNC_SIZE 4096
+
+
+enum MpegTSFilterType {
+    MPEGTS_PES,
+    MPEGTS_SECTION,
+};
+
+typedef void PESCallback(void *opaque, const uint8_t *buf, int len, int is_start);
+
+typedef struct MpegTSPESFilter {
+    PESCallback *pes_cb;
+    void *opaque;
+} MpegTSPESFilter;
+
+typedef void SectionCallback(void *opaque, const uint8_t *buf, int len);
+
+typedef void SetServiceCallback(void *opaque, int ret);
+
+typedef struct MpegTSSectionFilter {
+    int section_index;
+    int section_h_size;
+    uint8_t *section_buf;
+    int check_crc:1;
+    int end_of_section_reached:1;
+    SectionCallback *section_cb;
+    void *opaque;
+
+} MpegTSSectionFilter;
+
+typedef struct MpegTSSection {
+    int pid;
+    int cc;
+    void (*write_packet)(struct MpegTSSection *s, const uint8_t *packet);
+    void *opaque;
+} MpegTSSection;
+
+typedef struct MpegTSFilter {
+    int pid;
+    int last_cc;
+    enum MpegTSFilterType type;
+    union {
+        MpegTSPESFilter pes_filter;
+        MpegTSSectionFilter section_filter;
+    } u;
+} MpegTSFilter;
+
+/*
+ * unified with MpegTSService of mpegtsenc.c
+ */
+typedef struct MpegTSService {
+    int last_cc; /* last cc code (-1 if first packet) */
+    MpegTSSection pmt; /* MPEG2 pmt table context */
+    int pcr_pid;
+    int sid;           /* service ID */
+    int running:1;
+    char *provider_name;
+    char *name;
+} MpegTSService;
+
+struct MpegTSContext {
+    /* user data */
+    AVFormatContext *stream;
+    int raw_packet_size; /* raw packet size, including FEC if present */
+    int auto_guess; /* if true, all pids are analized to find streams */
+    int set_service_ret;
+
+    int mpeg2ts_raw;  /* force raw MPEG2 transport stream output, if possible */
+    int mpeg2ts_compute_pcr; /* compute exact PCR for each transport stream packet */
+
+    /* used to estimate the exact PCR */
+    int64_t cur_pcr;
+    int pcr_incr;
+    int pcr_pid;
+    
+    /* data needed to handle file based ts */
+    int stop_parse; /* stop parsing loop */
+    AVPacket *pkt; /* packet containing av data */
+
+    /******************************************/
+    /* private mpegts data */
+    /* scan context */
+    MpegTSFilter *sdt_filter;
+    int nb_services;
+    MpegTSService **services;
+    
+    /* set service context (XXX: allocated it ?) */
+    SetServiceCallback *set_service_cb;
+    void *set_service_opaque;
+    MpegTSFilter *pat_filter;
+    MpegTSFilter *pmt_filter;
+    int req_sid;
+
+    MpegTSFilter *pids[NB_PID_MAX];
+};
+
+typedef struct MpegTSContext MpegTSContext;
+static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type);
 unsigned int mpegts_crc32(const uint8_t *data, int len);
 extern AVOutputFormat mpegts_mux;
 
-typedef struct MpegTSContext MpegTSContext;
 
 MpegTSContext *mpegts_parse_open(AVFormatContext *s);
 int mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
-------------- next part --------------
--- ../FFMpeg-20050530/libavformat/avformat.h	2005-05-26 22:17:11.000000000 +0200
+++ libavformat/avformat.h	2005-05-30 12:46:30.000000000 +0200
@@ -117,6 +117,7 @@ typedef struct AVFormatParameters {
                                   immediately (RTSP only) */
     enum CodecID video_codec_id;
     enum CodecID audio_codec_id;
+    char selected_service[257]; // services have a maximum length of 256 chars. + '0'   
 } AVFormatParameters;
 
 #define AVFMT_NOFILE        0x0001 /* no file should be opened */



More information about the ffmpeg-devel mailing list