/*
- * MPEG2 transport stream (aka DVB) demux
+ * MPEG2 transport stream (aka DVB) demuxer
* Copyright (c) 2002-2003 Fabrice Bellard.
*
- * This library is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * FFmpeg 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; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
typedef struct MpegTSService {
int running:1;
- int sid;
- char *provider_name;
- char *name;
+ int sid; /**< MPEG Program Number of stream */
+ char *provider_name; /**< DVB Network name, "" if not DVB stream */
+ char *name; /**< DVB Service name, "MPEG Program [sid]" if not DVB stream*/
} 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 */
+ /** raw packet size, including FEC if present */
+ int raw_packet_size;
+ /** if true, all pids are analyzed to find streams */
+ int auto_guess;
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 */
+ /** force raw MPEG2 transport stream output, if possible */
+ int mpeg2ts_raw;
+ /** compute exact PCR for each transport stream packet */
+ int mpeg2ts_compute_pcr;
- /* used to estimate the exact PCR */
- int64_t cur_pcr;
- int pcr_incr;
- int pcr_pid;
+ int64_t cur_pcr; /**< used to estimate the exact PCR */
+ int pcr_incr; /**< used to estimate the exact PCR */
+ int pcr_pid; /**< used to estimate the exact PCR */
/* data needed to handle file based ts */
- int stop_parse; /* stop parsing loop */
- AVPacket *pkt; /* packet containing av data */
+ /** stop parsing loop */
+ int stop_parse;
+ /** packet containing Audio/Video data */
+ AVPacket *pkt;
/******************************************/
/* private mpegts data */
/* scan context */
MpegTSFilter *sdt_filter;
+ /** number of PMTs in the last PAT seen */
int nb_services;
+ /** list of PMTs in the last PAT seen */
MpegTSService **services;
/* set service context (XXX: allocated it ?) */
SetServiceCallback *set_service_cb;
void *set_service_opaque;
+ /** filter for the PAT */
MpegTSFilter *pat_filter;
+ /** filter for the PMT for the MPEG program number specified by req_sid */
MpegTSFilter *pmt_filter;
+ /** MPEG program number of stream we want to decode */
int req_sid;
+ /** filters for various streams specified by PMT + for the PAT and PMT */
MpegTSFilter *pids[NB_PID_MAX];
};
+/**
+ * Assembles PES packets out of TS packets, and then calls the "section_cb"
+ * function when they are complete.
+ */
static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,
const uint8_t *buf, int buf_size, int is_start)
{
}
}
-MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int pid,
+static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int pid,
SectionCallback *section_cb, void *opaque,
int check_crc)
MpegTSSectionFilter *sec;
#ifdef DEBUG_SI
- printf("Filter: pid=0x%x\n", pid);
+ av_log(ts->stream, AV_LOG_DEBUG, "Filter: pid=0x%x\n", pid);
#endif
if (pid >= NB_PID_MAX || ts->pids[pid])
return NULL;
return filter;
}
-MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid,
+static MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid,
PESCallback *pes_cb,
void *opaque)
{
return filter;
}
-void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
+static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
{
int pid;
MpegTSService *service;
#ifdef DEBUG_SI
- printf("new_service: sid=0x%04x provider='%s' name='%s'\n",
+ av_log(ts->stream, AV_LOG_DEBUG, "new_service: "
+ "sid=0x%04x provider='%s' name='%s'\n",
sid, provider_name, name);
#endif
char language[4];
#ifdef DEBUG_SI
- printf("PMT:\n");
- av_hex_dump(stdout, (uint8_t *)section, section_len);
+ av_log(ts->stream, AV_LOG_DEBUG, "PMT: len %i\n", section_len);
+ av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len);
#endif
p_end = section + section_len - 4;
p = section;
if (parse_section_header(h, &p, p_end) < 0)
return;
#ifdef DEBUG_SI
- printf("sid=0x%x sec_num=%d/%d\n", h->id, h->sec_num, h->last_sec_num);
+ av_log(ts->stream, AV_LOG_DEBUG, "sid=0x%x sec_num=%d/%d\n",
+ h->id, h->sec_num, h->last_sec_num);
#endif
if (h->tid != PMT_TID || (ts->req_sid >= 0 && h->id != ts->req_sid) )
return;
return;
ts->pcr_pid = pcr_pid;
#ifdef DEBUG_SI
- printf("pcr_pid=0x%x\n", pcr_pid);
+ av_log(ts->stream, AV_LOG_DEBUG, "pcr_pid=0x%x\n", pcr_pid);
#endif
program_info_length = get16(&p, p_end) & 0xfff;
if (program_info_length < 0)
desc_tag = get8(&p, desc_list_end);
if (desc_tag < 0)
break;
+ if (stream_type == STREAM_TYPE_PRIVATE_DATA) {
+ if((desc_tag == 0x6A) || (desc_tag == 0x7A)) {
+ /*assume DVB AC-3 Audio*/
+ stream_type = STREAM_TYPE_AUDIO_AC3;
+ } else if(desc_tag == 0x7B) {
+ /* DVB DTS audio */
+ stream_type = STREAM_TYPE_AUDIO_DTS;
+ }
+ }
desc_len = get8(&p, desc_list_end);
desc_end = p + desc_len;
if (desc_end > desc_list_end)
break;
#ifdef DEBUG_SI
- printf("tag: 0x%02x len=%d\n", desc_tag, desc_len);
+ av_log(ts->stream, AV_LOG_DEBUG, "tag: 0x%02x len=%d\n",
+ desc_tag, desc_len);
#endif
switch(desc_tag) {
case DVB_SUBT_DESCID:
p = desc_list_end;
#ifdef DEBUG_SI
- printf("stream_type=%d pid=0x%x\n", stream_type, pid);
+ av_log(ts->stream, AV_LOG_DEBUG, "stream_type=%d pid=0x%x\n",
+ stream_type, pid);
#endif
/* now create ffmpeg stream */
case STREAM_TYPE_VIDEO_MPEG2:
case STREAM_TYPE_VIDEO_MPEG4:
case STREAM_TYPE_VIDEO_H264:
+ case STREAM_TYPE_VIDEO_VC1:
case STREAM_TYPE_AUDIO_AAC:
case STREAM_TYPE_AUDIO_AC3:
case STREAM_TYPE_AUDIO_DTS:
int sid, pmt_pid;
#ifdef DEBUG_SI
- printf("PAT:\n");
- av_hex_dump(stdout, (uint8_t *)section, section_len);
+ av_log(ts->stream, AV_LOG_DEBUG, "PAT:\n");
+ av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len);
#endif
p_end = section + section_len - 4;
p = section;
if (pmt_pid < 0)
break;
#ifdef DEBUG_SI
- printf("sid=0x%x pid=0x%x\n", sid, pmt_pid);
+ av_log(ts->stream, AV_LOG_DEBUG, "sid=0x%x pid=0x%x\n", sid, pmt_pid);
#endif
if (sid == 0x0000) {
/* NIT info */
char buf[256];
#ifdef DEBUG_SI
- printf("PAT:\n");
- av_hex_dump(stdout, (uint8_t *)section, section_len);
+ av_log(ts->stream, AV_LOG_DEBUG, "PAT:\n");
+ av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len);
#endif
p_end = section + section_len - 4;
p = section;
if (pmt_pid < 0)
break;
#ifdef DEBUG_SI
- printf("sid=0x%x pid=0x%x\n", sid, pmt_pid);
+ av_log(ts->stream, AV_LOG_DEBUG, "sid=0x%x pid=0x%x\n", sid, pmt_pid);
#endif
if (sid == 0x0000) {
/* NIT info */
ts->pat_filter = NULL;
}
-void mpegts_set_service(MpegTSContext *ts, int sid,
+static void mpegts_set_service(MpegTSContext *ts, int sid,
SetServiceCallback *set_service_cb, void *opaque)
{
ts->set_service_cb = set_service_cb;
char *name, *provider_name;
#ifdef DEBUG_SI
- printf("SDT:\n");
- av_hex_dump(stdout, (uint8_t *)section, section_len);
+ av_log(ts->stream, AV_LOG_DEBUG, "SDT:\n");
+ av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len);
#endif
p_end = section + section_len - 4;
if (desc_end > desc_list_end)
break;
#ifdef DEBUG_SI
- printf("tag: 0x%02x len=%d\n", desc_tag, desc_len);
+ av_log(ts->stream, AV_LOG_DEBUG, "tag: 0x%02x len=%d\n",
+ desc_tag, desc_len);
#endif
switch(desc_tag) {
case 0x48:
}
/* scan services in a transport stream by looking at the SDT */
-void mpegts_scan_sdt(MpegTSContext *ts)
+static void mpegts_scan_sdt(MpegTSContext *ts)
{
ts->sdt_filter = mpegts_open_section_filter(ts, SDT_PID,
sdt_cb, ts, 1);
/* scan services in a transport stream by looking at the PAT (better
than nothing !) */
-void mpegts_scan_pat(MpegTSContext *ts)
+static void mpegts_scan_pat(MpegTSContext *ts)
{
ts->pat_filter = mpegts_open_section_filter(ts, PAT_PID,
pat_scan_cb, ts, 1);
/* we got all the PES or section header. We can now
decide */
#if 0
- av_hex_dump(pes->header, pes->data_index);
+ av_hex_dump_log(pes->stream, AV_LOG_DEBUG, pes->header, pes->data_index);
#endif
if (pes->header[0] == 0x00 && pes->header[1] == 0x00 &&
pes->header[2] == 0x01) {
code = pes->header[3] | 0x100;
if (!((code >= 0x1c0 && code <= 0x1df) ||
(code >= 0x1e0 && code <= 0x1ef) ||
- (code == 0x1bd)))
+ (code == 0x1bd) || (code == 0x1fd)))
goto skip;
if (!pes->st) {
/* allocate stream */
codec_type = CODEC_TYPE_VIDEO;
codec_id = CODEC_ID_H264;
break;
+ case STREAM_TYPE_VIDEO_VC1:
+ codec_type = CODEC_TYPE_VIDEO;
+ codec_id = CODEC_ID_VC1;
+ break;
case STREAM_TYPE_AUDIO_AAC:
codec_type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_AAC;
#endif
}
-void set_service_cb(void *opaque, int ret)
+static void set_service_cb(void *opaque, int ret)
{
MpegTSContext *ts = opaque;
ts->set_service_ret = ret;
url_fseek(pb, pos, SEEK_SET);
mpegts_scan_sdt(ts);
- handle_packets(ts, MAX_SCAN_PACKETS);
+ handle_packets(ts, s->probesize);
if (ts->nb_services <= 0) {
/* no SDT found, we try to look at the PAT */
url_fseek(pb, pos, SEEK_SET);
mpegts_scan_pat(ts);
- handle_packets(ts, MAX_SCAN_PACKETS);
+ handle_packets(ts, s->probesize);
}
if (ts->nb_services <= 0) {
service = ts->services[i];
sid = service->sid;
#ifdef DEBUG_SI
- printf("tuning to '%s'\n", service->name);
+ av_log(ts->stream, AV_LOG_DEBUG, "tuning to '%s'\n", service->name);
#endif
/* now find the info for the first service if we found any,
url_fseek(pb, pos, SEEK_SET);
mpegts_set_service(ts, sid, set_service_cb, ts);
- handle_packets(ts, MAX_SCAN_PACKETS);
+ handle_packets(ts, s->probesize);
}
/* if could not find service, exit */
}
#ifdef DEBUG_SI
- printf("tuning done\n");
+ av_log(ts->stream, AV_LOG_DEBUG, "tuning done\n");
#endif
}
s->ctx_flags |= AVFMTCTX_NOHEADER;
st->codec->bit_rate = s->bit_rate;
st->start_time = ts->cur_pcr;
#if 0
- printf("start=%0.3f pcr=%0.3f incr=%d\n",
+ av_log(ts->stream, AV_LOG_DEBUG, "start=%0.3f pcr=%0.3f incr=%d\n",
st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr);
#endif
}
uint8_t pcr_buf[12];
if (av_new_packet(pkt, TS_PACKET_SIZE) < 0)
- return -ENOMEM;
+ return AVERROR(ENOMEM);
pkt->pos= url_ftell(&s->pb);
ret = read_packet(&s->pb, pkt->data, ts->raw_packet_size);
if (ret < 0) {
int i;
for(i=0;i<NB_PID_MAX;i++)
if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]);
+
+ for(i = 0; i < ts->nb_services; i++){
+ av_free(ts->services[i]->provider_name);
+ av_free(ts->services[i]->name);
+ av_free(ts->services[i]);
+ }
+ av_freep(&ts->services);
+
return 0;
}
av_free(ts);
}
-AVInputFormat mpegts_demux = {
+AVInputFormat mpegts_demuxer = {
"mpegts",
"MPEG2 transport stream format",
sizeof(MpegTSContext),
mpegts_get_pcr,
.flags = AVFMT_SHOW_IDS,
};
-
-int mpegts_init(void)
-{
- av_register_input_format(&mpegts_demux);
-#ifdef CONFIG_MUXERS
- av_register_output_format(&mpegts_mux);
-#endif
- return 0;
-}