[Ffmpeg-devel] mpeg transport streams
Marcus Hunger
marcus.hunger
Wed Jun 1 17:43:12 CEST 2005
Fixed some issues. The reason for moving the structs is MpegTSService: two structs
with the same name, which I unified to one.
MUGLER AG
Entwicklung
E-mail: marcus.hunger at mugler.de
Tel. +49-3723-747-183
Fax: +49-3723-747-198
Bitte nutzen Sie die E-Mail-Verbindung mit uns aus-
schliesslich zum Informationsaustausch. Wir koennen
auf diesem Wege keine rechtsgeschaeftlichen Erklaer-
ungen (Auftraege etc.) entgegennehmen. Der Inhalt
dieser Nachricht ist vertraulich und nur fuer den an-
gegebenen Empfaenger bestimmt. Jede Form der Kennt-
nisnahme und Weitergabe durch Dritte ist unzulaessig.
Sollte diese Nachricht nicht fuer Sie bestimmt sein,
so bitten wir Sie, sich mit uns per E-Mail oder
telefonisch in Verbindung zu setzen.
Please use your E-mail connection with us exclusively
for the exchange of information. We do not accept
legally binding declarations (orders, etc) by this means
of communication. The content of this message is
confidential and intended only for the recipient
indicated. Taking notice of this message or disclosure
by third parties is not permitted. In the event
that this message is not intended for you,
please contact us via E-mail or phone.
-------------- next part --------------
--- ../FFMpeg-20050530/libavformat/mpegtsenc.c 2005-03-09 03:12:44.000000000 +0100
+++ libavformat/mpegtsenc.c 2005-06-01 17:59:40.000000000 +0200
@@ -82,12 +82,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)
@@ -190,36 +190,205 @@ int mpegts_write_section1(MpegTSSection
/* 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];
} 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 +406,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;
@@ -385,12 +573,25 @@ static int mpegts_write_header(AVFormatC
MpegTSService *service;
AVStream *st;
int i, total_bit_rate;
+ char *service_name;
+
+ 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 (s->title[0] == 0) {
+ service_name = DEFAULT_SERVICE_NAME;
+ } else {
+ service_name = s->title;
+ }
+
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 +605,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 +620,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 +633,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 +644,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,34 +677,103 @@ 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 (pts != AV_NOPTS_VALUE && ts->need_pcr && (pcrbase < pts)) {
+ mpegts_check_bitrate_underrun(s, pts, ts_st);
+ }
+
while (payload_size > 0) {
+
+ calc_pcr(ts, &pcrbase, &pcrext);
+
+ if (pts != AV_NOPTS_VALUE && 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 = buf;
+ q = fields[sync_flags_pid].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;
+ 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) {
+
/* write PES header */
+
*q++ = 0x00;
*q++ = 0x00;
*q++ = 0x01;
@@ -507,10 +786,18 @@ static void mpegts_write_pes(AVFormatCon
else
header_len = 3;
len = payload_size + header_len;
- *q++ = len >> 8;
- *q++ = 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) {
+ pts += 50000;
+
*q++ = 0x80; /* PTS only */
*q++ = 0x05; /* header len */
val = (0x02 << 4) |
@@ -528,52 +815,92 @@ static void mpegts_write_pes(AVFormatCon
}
is_start = 0;
}
+
/* write header */
- ts_len = q - buf;
- put_buffer(&s->pb, buf, ts_len);
+ peshead_len = q - fields[pes].buf;
+
+
/* write data */
- len = TS_PACKET_SIZE - ts_len;
+ 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;
- put_buffer(&s->pb, payload, len);
+ memcpy(fields[pes].buf + peshead_len, payload, len);
+ fields[pes].len = len + peshead_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);
+ 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;
- while (size > 0) {
- len = DEFAULT_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)
+ if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
+ ts->need_pcr = 1;
+
+ mpegts_write_pes(s, st, buf, size, pkt->pts);
+
+ } else {
+ ts->need_pcr = 0;
+
+ while (size > 0) {
+ len = DEFAULT_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;
+
ts_st->payload_pts = pkt->pts;
- if (ts_st->payload_index >= DEFAULT_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;
}
}
+
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