diff options
Diffstat (limited to 'libavformat/mpegts.c')
-rw-r--r-- | libavformat/mpegts.c | 216 |
1 files changed, 132 insertions, 84 deletions
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index f7045cee5e..8d026fd372 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]; @@ -456,7 +468,7 @@ static inline int get16(const uint8_t **pp, const uint8_t *p_end) return c; } -/* read and allocate a DVB string preceeded by its length */ +/* read and allocate a DVB string preceded by its length */ static char *getstr8(const uint8_t **pp, const uint8_t *p_end) { int len; @@ -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; } @@ -808,10 +838,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; @@ -1281,15 +1311,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 */ @@ -1352,6 +1384,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; } @@ -1393,6 +1428,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); @@ -1428,7 +1464,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; @@ -1506,6 +1542,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); @@ -1517,6 +1554,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); @@ -1531,7 +1570,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); @@ -1659,7 +1700,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) { @@ -1672,7 +1713,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) return 0; p = packet + 4; if (has_adaptation) { - /* skip adapation field */ + /* skip adaptation field */ p += p[0] + 1; } /* if past the end of packet, ignore */ @@ -1728,7 +1769,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); @@ -1750,7 +1791,7 @@ static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size) len = avio_read(pb, buf, TS_PACKET_SIZE); if (len != TS_PACKET_SIZE) return len < 0 ? len : AVERROR_EOF; - /* check paquet sync byte */ + /* check packet sync byte */ if (buf[0] != 0x47) { /* find a new packet start */ avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR); @@ -1794,11 +1835,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,27 +1919,32 @@ 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; if (s->iformat == &ff_mpegts_demuxer) { /* normal demux */ - /* first do a scaning 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"); + /* first do a scanning to get all the services */ + /* 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(×tamp, &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(×tamp, &pcr_l, buf) == 0) { - break; + if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) && + parse_pcr(×tamp, &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, timestamp; + 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, |