summaryrefslogtreecommitdiffstats
path: root/libavformat/mpegts.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/mpegts.c')
-rw-r--r--libavformat/mpegts.c208
1 files changed, 128 insertions, 80 deletions
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index b105d8c..81649c7 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -2,20 +2,20 @@
* MPEG2 transport stream (aka DVB) demuxer
* Copyright (c) 2002-2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.1 of the License, or (at your option) any later version.
*
- * Libav 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 Libav; 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
*/
@@ -27,6 +27,7 @@
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/get_bits.h"
#include "avformat.h"
@@ -227,6 +228,17 @@ static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned i
p->pids[p->nb_pids++] = pid;
}
+static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid)
+{
+ int i;
+ for(i=0; i<s->nb_programs; i++) {
+ if(s->programs[i]->id == programid) {
+ s->programs[i]->pcr_pid = pid;
+ break;
+ }
+ }
+}
+
/**
* @brief discard_pid() decides if the pid is to be discarded according
* to caller's programs selection
@@ -387,7 +399,7 @@ static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
memset(stat, 0, packet_size*sizeof(int));
for(x=i=0; i<size-3; i++){
- if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && (buf[i+3] & 0x30)){
+ if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){
stat[x]++;
if(stat[x] > best_score){
best_score= stat[x];
@@ -521,7 +533,9 @@ static const StreamType ISO_types[] = {
{ 0x04, AVMEDIA_TYPE_AUDIO, CODEC_ID_MP3 },
{ 0x0f, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC },
{ 0x10, AVMEDIA_TYPE_VIDEO, CODEC_ID_MPEG4 },
- { 0x11, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC_LATM }, /* LATM syntax */
+ /* Makito encoder sets stream type 0x11 for AAC,
+ * so auto-detect LOAS/LATM instead of hardcoding it. */
+// { 0x11, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC_LATM }, /* LATM syntax */
{ 0x1b, AVMEDIA_TYPE_VIDEO, CODEC_ID_H264 },
{ 0xd1, AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC },
{ 0xea, AVMEDIA_TYPE_VIDEO, CODEC_ID_VC1 },
@@ -534,6 +548,10 @@ static const StreamType HDMV_types[] = {
{ 0x82, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS },
{ 0x83, AVMEDIA_TYPE_AUDIO, CODEC_ID_TRUEHD },
{ 0x84, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 },
+ { 0x85, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS HD */
+ { 0x86, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS HD MASTER*/
+ { 0xa1, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */
+ { 0xa2, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS Express Secondary Audio */
{ 0x90, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_HDMV_PGS_SUBTITLE },
{ 0 },
};
@@ -549,6 +567,10 @@ static const StreamType REGD_types[] = {
{ MKTAG('d','r','a','c'), AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC },
{ MKTAG('A','C','-','3'), AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 },
{ MKTAG('B','S','S','D'), AVMEDIA_TYPE_AUDIO, CODEC_ID_S302M },
+ { MKTAG('D','T','S','1'), AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS },
+ { MKTAG('D','T','S','2'), AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS },
+ { MKTAG('D','T','S','3'), AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS },
+ { MKTAG('V','C','-','1'), AVMEDIA_TYPE_VIDEO, CODEC_ID_VC1 },
{ 0 },
};
@@ -569,6 +591,7 @@ static void mpegts_find_stream_type(AVStream *st,
if (stream_type == types->stream_type) {
st->codec->codec_type = types->codec_type;
st->codec->codec_id = types->codec_id;
+ st->request_probe = 0;
return;
}
}
@@ -577,6 +600,8 @@ static void mpegts_find_stream_type(AVStream *st,
static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
uint32_t stream_type, uint32_t prog_reg_desc)
{
+ int old_codec_type= st->codec->codec_type;
+ int old_codec_id = st->codec->codec_id;
avpriv_set_pts_info(st, 33, 1, 90000);
st->priv_data = pes;
st->codec->codec_type = AVMEDIA_TYPE_DATA;
@@ -592,7 +617,8 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
st->codec->codec_tag = pes->stream_type;
mpegts_find_stream_type(st, pes->stream_type, ISO_types);
- if (prog_reg_desc == AV_RL32("HDMV") &&
+ if ((prog_reg_desc == AV_RL32("HDMV") ||
+ prog_reg_desc == AV_RL32("HDPR")) &&
st->codec->codec_id == CODEC_ID_NONE) {
mpegts_find_stream_type(st, pes->stream_type, HDMV_types);
if (pes->stream_type == 0x83) {
@@ -622,6 +648,10 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
}
if (st->codec->codec_id == CODEC_ID_NONE)
mpegts_find_stream_type(st, pes->stream_type, MISC_types);
+ if (st->codec->codec_id == CODEC_ID_NONE){
+ st->codec->codec_id = old_codec_id;
+ st->codec->codec_type= old_codec_type;
+ }
return 0;
}
@@ -809,10 +839,10 @@ static int mpegts_push_data(MpegTSFilter *filter,
code != 0x1ff && code != 0x1f2 && /* program_stream_directory, DSMCC_stream */
code != 0x1f8) { /* ITU-T Rec. H.222.1 type E stream */
pes->state = MPEGTS_PESHEADER;
- if (pes->st->codec->codec_id == CODEC_ID_NONE) {
+ if (pes->st->codec->codec_id == CODEC_ID_NONE && !pes->st->request_probe) {
av_dlog(pes->stream, "pid=%x stream_type=%x probing\n",
pes->pid, pes->stream_type);
- pes->st->codec->codec_id = CODEC_ID_PROBE;
+ pes->st->request_probe= 1;
}
} else {
pes->state = MPEGTS_PAYLOAD;
@@ -1282,15 +1312,17 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
break;
case 0x1F: /* FMC descriptor */
get16(pp, desc_end);
- if (mp4_descr_count > 0 && st->codec->codec_id == CODEC_ID_AAC_LATM &&
+ if (mp4_descr_count > 0 && (st->codec->codec_id == CODEC_ID_AAC_LATM || st->request_probe>0) &&
mp4_descr->dec_config_descr_len && mp4_descr->es_id == pid) {
AVIOContext pb;
ffio_init_context(&pb, mp4_descr->dec_config_descr,
mp4_descr->dec_config_descr_len, 0, NULL, NULL, NULL, NULL);
ff_mp4_read_dec_config_descr(fc, st, &pb);
if (st->codec->codec_id == CODEC_ID_AAC &&
- st->codec->extradata_size > 0)
- st->need_parsing = 0;
+ st->codec->extradata_size > 0){
+ st->request_probe= st->need_parsing = 0;
+ st->codec->codec_type= AVMEDIA_TYPE_AUDIO;
+ }
}
break;
case 0x56: /* DVB teletext descriptor */
@@ -1353,6 +1385,9 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
stream_type == STREAM_TYPE_PRIVATE_DATA)
mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types);
break;
+ case 0x52: /* stream identifier descriptor */
+ st->stream_identifier = 1 + get8(pp, desc_end);
+ break;
default:
break;
}
@@ -1394,6 +1429,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (pcr_pid < 0)
return;
add_pid_to_pmt(ts, h->id, pcr_pid);
+ set_pcr_pid(ts->stream, h->id, pcr_pid);
av_dlog(ts->stream, "pcr_pid=0x%x\n", pcr_pid);
@@ -1429,7 +1465,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
// stop parsing after pmt, we found header
if (!ts->stream->nb_streams)
- ts->stop_parse = 1;
+ ts->stop_parse = 2;
for(;;) {
st = 0;
@@ -1507,6 +1543,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end;
int sid, pmt_pid;
+ AVProgram *program;
av_dlog(ts->stream, "PAT:\n");
hex_dump_debug(ts->stream, (uint8_t *)section, section_len);
@@ -1518,6 +1555,8 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (h->tid != PAT_TID)
return;
+ ts->stream->ts_id = h->id;
+
clear_programs(ts);
for(;;) {
sid = get16(&p, p_end);
@@ -1532,7 +1571,9 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
if (sid == 0x0000) {
/* NIT info */
} else {
- av_new_program(ts->stream, sid);
+ program = av_new_program(ts->stream, sid);
+ program->program_num = sid;
+ program->pmt_pid = pmt_pid;
if (ts->pids[pmt_pid])
mpegts_close_filter(ts, ts->pids[pmt_pid]);
mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
@@ -1660,7 +1701,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
tss->last_cc = cc;
if (!cc_ok) {
- av_log(ts->stream, AV_LOG_WARNING,
+ av_log(ts->stream, AV_LOG_DEBUG,
"Continuity check failed for pid %d expected %d got %d\n",
pid, expected_cc, cc);
if(tss->type == MPEGTS_PES) {
@@ -1729,7 +1770,7 @@ static int mpegts_resync(AVFormatContext *s)
for(i = 0;i < MAX_RESYNC_SIZE; i++) {
c = avio_r8(pb);
- if (pb->eof_reached)
+ if (url_feof(pb))
return -1;
if (c == 0x47) {
avio_seek(pb, -1, SEEK_CUR);
@@ -1795,11 +1836,15 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
ts->stop_parse = 0;
packet_num = 0;
for(;;) {
- if (ts->stop_parse>0)
- break;
packet_num++;
- if (nb_packets != 0 && packet_num >= nb_packets)
+ if (nb_packets != 0 && packet_num >= nb_packets ||
+ ts->stop_parse > 1) {
+ ret = AVERROR(EAGAIN);
+ break;
+ }
+ if (ts->stop_parse > 0)
break;
+
ret = read_packet(s, packet, ts->raw_packet_size);
if (ret != 0)
break;
@@ -1874,18 +1919,20 @@ static int mpegts_read_header(AVFormatContext *s)
{
MpegTSContext *ts = s->priv_data;
AVIOContext *pb = s->pb;
- uint8_t buf[5*1024];
+ uint8_t buf[8*1024];
int len;
int64_t pos;
- /* read the first 1024 bytes to get packet size */
+ /* read the first 8192 bytes to get packet size */
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
if (len != sizeof(buf))
goto fail;
ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
- if (ts->raw_packet_size <= 0)
- goto fail;
+ if (ts->raw_packet_size <= 0) {
+ av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n");
+ ts->raw_packet_size = TS_PACKET_SIZE;
+ }
ts->stream = s;
ts->auto_guess = 0;
@@ -1893,8 +1940,11 @@ static int mpegts_read_header(AVFormatContext *s)
/* normal demux */
/* first do a scan to get all the services */
- if (pb->seekable && avio_seek(pb, pos, SEEK_SET) < 0)
- av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n");
+ /* NOTE: We attempt to seek on non-seekable files as well, as the
+ * probe buffer usually is big enough. Only warn if the seek failed
+ * on files where the seek should work. */
+ if (avio_seek(pb, pos, SEEK_SET) < 0)
+ av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
@@ -2054,36 +2104,58 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
int64_t pos, timestamp;
uint8_t buf[TS_PACKET_SIZE];
int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid;
- const int find_next= 1;
pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
- if (find_next) {
- for(;;) {
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
+ while(pos < pos_limit) {
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+ if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
+ return AV_NOPTS_VALUE;
+ if (buf[0] != 0x47) {
+ if (mpegts_resync(s) < 0)
return AV_NOPTS_VALUE;
- if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
- parse_pcr(&timestamp, &pcr_l, buf) == 0) {
- break;
- }
- pos += ts->raw_packet_size;
+ pos = avio_tell(s->pb);
+ continue;
}
- } else {
- for(;;) {
- pos -= ts->raw_packet_size;
- if (pos < 0)
- return AV_NOPTS_VALUE;
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
- return AV_NOPTS_VALUE;
- if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
- parse_pcr(&timestamp, &pcr_l, buf) == 0) {
- break;
+ if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
+ parse_pcr(&timestamp, &pcr_l, buf) == 0) {
+ *ppos = pos;
+ return timestamp;
+ }
+ pos += ts->raw_packet_size;
+ }
+
+ return AV_NOPTS_VALUE;
+}
+
+static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index,
+ int64_t *ppos, int64_t pos_limit)
+{
+ MpegTSContext *ts = s->priv_data;
+ int64_t pos;
+ pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
+ ff_read_frame_flush(s);
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+ while(pos < pos_limit) {
+ int ret;
+ AVPacket pkt;
+ av_init_packet(&pkt);
+ ret= av_read_frame(s, &pkt);
+ if(ret < 0)
+ return AV_NOPTS_VALUE;
+ av_free_packet(&pkt);
+ if(pkt.dts != AV_NOPTS_VALUE && pkt.pos >= 0){
+ ff_reduce_index(s, pkt.stream_index);
+ av_add_index_entry(s->streams[pkt.stream_index], pkt.pos, pkt.dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */);
+ if(pkt.stream_index == stream_index){
+ *ppos= pkt.pos;
+ return pkt.dts;
}
}
+ pos = pkt.pos;
}
- *ppos = pos;
- return timestamp;
+ return AV_NOPTS_VALUE;
}
#ifdef USE_SYNCPOINT_SEARCH
@@ -2170,31 +2242,6 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, in
return ret;
}
-#else
-
-static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
- MpegTSContext *ts = s->priv_data;
- uint8_t buf[TS_PACKET_SIZE];
- int64_t pos;
-
- if (ff_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
- return -1;
-
- pos= avio_tell(s->pb);
-
- for(;;) {
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
- return -1;
-// pid = AV_RB16(buf + 1) & 0x1fff;
- if(buf[1] & 0x40) break;
- pos += ts->raw_packet_size;
- }
- avio_seek(s->pb, pos, SEEK_SET);
-
- return 0;
-}
-
#endif
/**************************************************************/
@@ -2211,6 +2258,9 @@ MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s)
ts->raw_packet_size = TS_PACKET_SIZE;
ts->stream = s;
ts->auto_guess = 1;
+ mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
+ mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
+
return ts;
}
@@ -2223,10 +2273,8 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
len1 = len;
ts->pkt = pkt;
- ts->stop_parse = 0;
for(;;) {
- if (ts->stop_parse>0)
- break;
+ ts->stop_parse = 0;
if (len < TS_PACKET_SIZE)
return -1;
if (buf[0] != 0x47) {
@@ -2236,6 +2284,8 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
handle_packet(ts, buf);
buf += TS_PACKET_SIZE;
len -= TS_PACKET_SIZE;
+ if (ts->stop_parse == 1)
+ break;
}
}
return len1 - len;
@@ -2258,8 +2308,7 @@ AVInputFormat ff_mpegts_demuxer = {
.read_header = mpegts_read_header,
.read_packet = mpegts_read_packet,
.read_close = mpegts_read_close,
- .read_seek = read_seek,
- .read_timestamp = mpegts_get_pcr,
+ .read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
#ifdef USE_SYNCPOINT_SEARCH
.read_seek2 = read_seek2,
@@ -2273,8 +2322,7 @@ AVInputFormat ff_mpegtsraw_demuxer = {
.read_header = mpegts_read_header,
.read_packet = mpegts_raw_read_packet,
.read_close = mpegts_read_close,
- .read_seek = read_seek,
- .read_timestamp = mpegts_get_pcr,
+ .read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
#ifdef USE_SYNCPOINT_SEARCH
.read_seek2 = read_seek2,
OpenPOWER on IntegriCloud