[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