X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmpegts.c;h=50d4d5e9bc6b8853a5eb220cfac3d1caf89d15de;hb=d63f8c873bd65f4dfab852069fb5faf07cffe6aa;hp=edf6b5701df482111f008249373222dd000de176;hpb=1b98bfb932ad36667ea7f18e24c54978623f6654;p=ffmpeg diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index edf6b5701df..50d4d5e9bc6 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -28,6 +28,7 @@ #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/avassert.h" +#include "libavutil/dovi_meta.h" #include "libavcodec/bytestream.h" #include "libavcodec/get_bits.h" #include "libavcodec/opus.h" @@ -37,6 +38,9 @@ #include "avio_internal.h" #include "mpeg.h" #include "isom.h" +#if CONFIG_ICONV +#include +#endif /* maximum size in which we look for synchronization if * synchronization is lost */ @@ -53,6 +57,9 @@ (prev_dividend) = (dividend); \ } while (0) +#define PROBE_PACKET_MAX_BUF 8192 +#define PROBE_PACKET_MARGIN 5 + enum MpegTSFilterType { MPEGTS_PES, MPEGTS_SECTION, @@ -91,6 +98,7 @@ struct MpegTSFilter { int es_id; int last_cc; /* last cc code (-1 if first packet) */ int64_t last_pcr; + int discard; enum MpegTSFilterType type; union { MpegTSPESFilter pes_filter; @@ -115,10 +123,6 @@ struct MpegTSContext { /** raw packet size, including FEC if present */ int raw_packet_size; - int size_stat[3]; - int size_stat_count; -#define SIZE_STAT_THRESHOLD 10 - int64_t pos47_full; /** if true, all pids are analyzed to find streams */ @@ -161,6 +165,9 @@ struct MpegTSContext { /** filters for various streams specified by PMT + for the PAT and PMT */ MpegTSFilter *pids[NB_PID_MAX]; int current_pid; + + AVStream *epg_stream; + AVBufferPool* pools[32]; }; #define MPEGTS_OPTIONS \ @@ -503,20 +510,22 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, { MpegTSFilter *filter; MpegTSSectionFilter *sec; + uint8_t *section_buf = av_mallocz(MAX_SECTION_SIZE); - if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION))) + if (!section_buf) return NULL; + + if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION))) { + av_free(section_buf); + return NULL; + } sec = &filter->u.section_filter; sec->section_cb = section_cb; sec->opaque = opaque; - sec->section_buf = av_mallocz(MAX_SECTION_SIZE); + sec->section_buf = section_buf; sec->check_crc = check_crc; sec->last_ver = -1; - if (!sec->section_buf) { - av_free(filter); - return NULL; - } return filter; } @@ -590,28 +599,42 @@ static int analyze(const uint8_t *buf, int size, int packet_size, return best_score - FFMAX(stat_all - 10*best_score, 0)/10; } -/* autodetect fec presence. Must have at least 1024 bytes */ -static int get_packet_size(const uint8_t *buf, int size) +/* autodetect fec presence */ +static int get_packet_size(AVFormatContext* s) { int score, fec_score, dvhs_score; + int margin; + int ret; - if (size < (TS_FEC_PACKET_SIZE * 5 + 1)) - return AVERROR_INVALIDDATA; + /*init buffer to store stream for probing */ + uint8_t buf[PROBE_PACKET_MAX_BUF] = {0}; + int buf_size = 0; - score = analyze(buf, size, TS_PACKET_SIZE, 0); - dvhs_score = analyze(buf, size, TS_DVHS_PACKET_SIZE, 0); - fec_score = analyze(buf, size, TS_FEC_PACKET_SIZE, 0); - av_log(NULL, AV_LOG_TRACE, "score: %d, dvhs_score: %d, fec_score: %d \n", - score, dvhs_score, fec_score); - - if (score > fec_score && score > dvhs_score) - return TS_PACKET_SIZE; - else if (dvhs_score > score && dvhs_score > fec_score) - return TS_DVHS_PACKET_SIZE; - else if (score < fec_score && dvhs_score < fec_score) - return TS_FEC_PACKET_SIZE; - else - return AVERROR_INVALIDDATA; + while (buf_size < PROBE_PACKET_MAX_BUF) { + ret = avio_read_partial(s->pb, buf + buf_size, PROBE_PACKET_MAX_BUF - buf_size); + if (ret < 0) + return AVERROR_INVALIDDATA; + buf_size += ret; + + score = analyze(buf, buf_size, TS_PACKET_SIZE, 0); + dvhs_score = analyze(buf, buf_size, TS_DVHS_PACKET_SIZE, 0); + fec_score = analyze(buf, buf_size, TS_FEC_PACKET_SIZE, 0); + av_log(s, AV_LOG_TRACE, "Probe: %d, score: %d, dvhs_score: %d, fec_score: %d \n", + buf_size, score, dvhs_score, fec_score); + + margin = mid_pred(score, fec_score, dvhs_score); + + if (buf_size < PROBE_PACKET_MAX_BUF) + margin += PROBE_PACKET_MARGIN; /*if buffer not filled */ + + if (score > margin) + return TS_PACKET_SIZE; + else if (dvhs_score > margin) + return TS_DVHS_PACKET_SIZE; + else if (fec_score > margin) + return TS_FEC_PACKET_SIZE; + } + return AVERROR_INVALIDDATA; } typedef struct SectionHeader { @@ -673,6 +696,51 @@ static char *getstr8(const uint8_t **pp, const uint8_t *p_end) return NULL; if (len > p_end - p) return NULL; +#if CONFIG_ICONV + if (len) { + const char *encodings[] = { + "ISO6937", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", + "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", + "", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "", "", "", "", + "", "UCS-2BE", "KSC_5601", "GB2312", "UCS-2BE", "UTF-8", "", "", + "", "", "", "", "", "", "", "" + }; + iconv_t cd; + char *in, *out; + size_t inlen = len, outlen = inlen * 6 + 1; + if (len >= 3 && p[0] == 0x10 && !p[1] && p[2] && p[2] <= 0xf && p[2] != 0xc) { + char iso8859[12]; + snprintf(iso8859, sizeof(iso8859), "ISO-8859-%d", p[2]); + inlen -= 3; + in = (char *)p + 3; + cd = iconv_open("UTF-8", iso8859); + } else if (p[0] < 0x20) { + inlen -= 1; + in = (char *)p + 1; + cd = iconv_open("UTF-8", encodings[*p]); + } else { + in = (char *)p; + cd = iconv_open("UTF-8", encodings[0]); + } + if (cd == (iconv_t)-1) + goto no_iconv; + str = out = av_malloc(outlen); + if (!str) { + iconv_close(cd); + return NULL; + } + if (iconv(cd, &in, &inlen, &out, &outlen) == -1) { + iconv_close(cd); + av_freep(&str); + goto no_iconv; + } + iconv_close(cd); + *out = 0; + *pp = p + len; + return str; + } +no_iconv: +#endif str = av_malloc(len + 1); if (!str) return NULL; @@ -737,6 +805,7 @@ static const StreamType ISO_types[] = { { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, { 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, + { 0xd2, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_AVS2 }, { 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, { 0 }, }; @@ -918,7 +987,7 @@ static void new_data_packet(const uint8_t *buffer, int len, AVPacket *pkt) static int new_pes_packet(PESContext *pes, AVPacket *pkt) { - char *sd; + uint8_t *sd; av_init_packet(pkt); @@ -1034,6 +1103,18 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, return (get_bits_count(&gb) + 7) >> 3; } +static AVBufferRef *buffer_pool_get(MpegTSContext *ts, int size) +{ + int index = av_log2(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!ts->pools[index]) { + int pool_size = FFMIN(MAX_PES_PAYLOAD + AV_INPUT_BUFFER_PADDING_SIZE, 2 << index); + ts->pools[index] = av_buffer_pool_init(pool_size, NULL); + if (!ts->pools[index]) + return NULL; + } + return av_buffer_pool_get(ts->pools[index]); +} + /* return non zero if a packet could be constructed */ static int mpegts_push_data(MpegTSFilter *filter, const uint8_t *buf, int buf_size, int is_start, @@ -1108,8 +1189,7 @@ static int mpegts_push_data(MpegTSFilter *filter, pes->total_size = MAX_PES_PAYLOAD; /* allocate pes buffer */ - pes->buffer = av_buffer_alloc(pes->total_size + - AV_INPUT_BUFFER_PADDING_SIZE); + pes->buffer = buffer_pool_get(ts, pes->total_size); if (!pes->buffer) return AVERROR(ENOMEM); @@ -1219,6 +1299,7 @@ skip: || pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE) ) { AVProgram *p = NULL; + int pcr_found = 0; while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) { if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) { MpegTSFilter *f = pes->ts->pids[p->pcr_pid]; @@ -1236,14 +1317,17 @@ skip: st = pst; } } - if (f->last_pcr != -1 && st && st->discard != AVDISCARD_ALL) { + if (f->last_pcr != -1 && !f->discard) { // teletext packets do not always have correct timestamps, // the standard says they should be handled after 40.6 ms at most, // and the pcr error to this packet should be no more than 100 ms. // TODO: we should interpolate the PCR, not just use the last one int64_t pcr = f->last_pcr / 300; - pes->st->pts_wrap_reference = st->pts_wrap_reference; - pes->st->pts_wrap_behavior = st->pts_wrap_behavior; + pcr_found = 1; + if (st) { + pes->st->pts_wrap_reference = st->pts_wrap_reference; + pes->st->pts_wrap_behavior = st->pts_wrap_behavior; + } if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) { pes->pts = pes->dts = pcr; } else if (pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT && @@ -1258,6 +1342,16 @@ skip: } } } + + if (pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT && + !pcr_found) { + av_log(pes->stream, AV_LOG_VERBOSE, + "Forcing DTS/PTS to be unset for a " + "non-trustworthy PES packet for PID %d as " + "PCR hasn't been received yet.\n", + pes->pid); + pes->dts = pes->pts = AV_NOPTS_VALUE; + } } } break; @@ -1269,8 +1363,7 @@ skip: if (ret < 0) return ret; pes->total_size = MAX_PES_PAYLOAD; - pes->buffer = av_buffer_alloc(pes->total_size + - AV_INPUT_BUFFER_PADDING_SIZE); + pes->buffer = buffer_pool_get(ts, pes->total_size); if (!pes->buffer) return AVERROR(ENOMEM); ts->stop_parse = 1; @@ -1646,6 +1739,13 @@ static void scte_data_cb(MpegTSFilter *filter, const uint8_t *section, if (idx < 0) return; + /** + * In case we receive an SCTE-35 packet before mpegts context is fully + * initialized. + */ + if (!ts->pkt) + return; + new_data_packet(section, section_len, ts->pkt); ts->pkt->stream_index = idx; prg = av_find_program_from_stream(ts->stream, NULL, idx); @@ -1756,7 +1856,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type case 0x56: /* DVB teletext descriptor */ { uint8_t *extradata = NULL; - int language_count = desc_len / 5; + int language_count = desc_len / 5, ret; if (desc_len > 0 && desc_len % 5 != 0) return AVERROR_INVALIDDATA; @@ -1766,9 +1866,9 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type av_assert0(language_count <= sizeof(language) / 4); if (st->codecpar->extradata == NULL) { - if (ff_alloc_extradata(st->codecpar, language_count * 2)) { - return AVERROR(ENOMEM); - } + ret = ff_alloc_extradata(st->codecpar, language_count * 2); + if (ret < 0) + return ret; } if (st->codecpar->extradata_size < language_count * 2) @@ -1801,7 +1901,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type * subtitling_type (1 byte), * composition_page_id (2 bytes), * ancillary_page_id (2 bytes) */ - int language_count = desc_len / 8; + int language_count = desc_len / 8, ret; if (desc_len > 0 && desc_len % 8 != 0) return AVERROR_INVALIDDATA; @@ -1817,9 +1917,9 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type av_assert0(language_count <= sizeof(language) / 4); if (st->codecpar->extradata == NULL) { - if (ff_alloc_extradata(st->codecpar, language_count * 5)) { - return AVERROR(ENOMEM); - } + ret = ff_alloc_extradata(st->codecpar, language_count * 5); + if (ret < 0) + return ret; } if (st->codecpar->extradata_size < language_count * 5) @@ -2002,6 +2102,97 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type } } break; + case 0xfd: /* ARIB data coding type descriptor */ + // STD-B24, fascicle 3, chapter 4 defines private_stream_1 + // for captions + if (stream_type == STREAM_TYPE_PRIVATE_DATA) { + // This structure is defined in STD-B10, part 1, listing 5.4 and + // part 2, 6.2.20). + // Listing of data_component_ids is in STD-B10, part 2, Annex J. + // Component tag limits are documented in TR-B14, fascicle 2, + // Vol. 3, Section 2, 4.2.8.1 + int actual_component_tag = st->stream_identifier - 1; + int picked_profile = FF_PROFILE_UNKNOWN; + int data_component_id = get16(pp, desc_end); + if (data_component_id < 0) + return AVERROR_INVALIDDATA; + + switch (data_component_id) { + case 0x0008: + // [0x30..0x37] are component tags utilized for + // non-mobile captioning service ("profile A"). + if (actual_component_tag >= 0x30 && + actual_component_tag <= 0x37) { + picked_profile = FF_PROFILE_ARIB_PROFILE_A; + } + break; + case 0x0012: + // component tag 0x87 signifies a mobile/partial reception + // (1seg) captioning service ("profile C"). + if (actual_component_tag == 0x87) { + picked_profile = FF_PROFILE_ARIB_PROFILE_C; + } + break; + default: + break; + } + + if (picked_profile == FF_PROFILE_UNKNOWN) + break; + + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_ARIB_CAPTION; + st->codecpar->profile = picked_profile; + st->request_probe = 0; + } + break; + case 0xb0: /* DOVI video stream descriptor */ + { + uint32_t buf; + AVDOVIDecoderConfigurationRecord *dovi; + size_t dovi_size; + int ret; + if (desc_end - *pp < 4) // (8 + 8 + 7 + 6 + 1 + 1 + 1) / 8 + return AVERROR_INVALIDDATA; + + dovi = av_dovi_alloc(&dovi_size); + if (!dovi) + return AVERROR(ENOMEM); + + dovi->dv_version_major = get8(pp, desc_end); + dovi->dv_version_minor = get8(pp, desc_end); + buf = get16(pp, desc_end); + dovi->dv_profile = (buf >> 9) & 0x7f; // 7 bits + dovi->dv_level = (buf >> 3) & 0x3f; // 6 bits + dovi->rpu_present_flag = (buf >> 2) & 0x01; // 1 bit + dovi->el_present_flag = (buf >> 1) & 0x01; // 1 bit + dovi->bl_present_flag = buf & 0x01; // 1 bit + if (desc_end - *pp >= 20) { // 4 + 4 * 4 + buf = get8(pp, desc_end); + dovi->dv_bl_signal_compatibility_id = (buf >> 4) & 0x0f; // 4 bits + } else { + // 0 stands for None + // Dolby Vision V1.2.93 profiles and levels + dovi->dv_bl_signal_compatibility_id = 0; + } + + ret = av_stream_add_side_data(st, AV_PKT_DATA_DOVI_CONF, + (uint8_t *)dovi, dovi_size); + if (ret < 0) { + av_free(dovi); + return ret; + } + + av_log(fc, AV_LOG_TRACE, "DOVI, version: %d.%d, profile: %d, level: %d, " + "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d\n", + dovi->dv_version_major, dovi->dv_version_minor, + dovi->dv_profile, dovi->dv_level, + dovi->rpu_present_flag, + dovi->el_present_flag, + dovi->bl_present_flag, + dovi->dv_bl_signal_compatibility_id); + } + break; default: break; } @@ -2009,7 +2200,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type return 0; } -static AVStream *find_matching_stream(MpegTSContext *ts, int pid, +static AVStream *find_matching_stream(MpegTSContext *ts, int pid, unsigned int programid, int stream_identifier, int pmt_stream_idx) { AVFormatContext *s = ts->stream; @@ -2018,6 +2209,8 @@ static AVStream *find_matching_stream(MpegTSContext *ts, int pid, for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; + if (st->program_num != programid) + continue; if (stream_identifier != -1) { /* match based on "stream identifier descriptor" if present */ if (st->stream_identifier == stream_identifier+1) { found = st; @@ -2188,7 +2381,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { pes = ts->pids[pid]->u.pes_filter.opaque; if (ts->merge_pmt_versions && !pes->st) { - st = find_matching_stream(ts, pid, stream_identifier, i); + st = find_matching_stream(ts, pid, h->id, stream_identifier, i); if (st) { pes->st = st; pes->stream_type = stream_type; @@ -2210,7 +2403,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid); if (ts->merge_pmt_versions && pes && !pes->st) { - st = find_matching_stream(ts, pid, stream_identifier, i); + st = find_matching_stream(ts, pid, h->id, stream_identifier, i); if (st) { pes->st = st; pes->stream_type = stream_type; @@ -2232,7 +2425,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len st = ts->stream->streams[idx]; } if (ts->merge_pmt_versions && !st) { - st = find_matching_stream(ts, pid, stream_identifier, i); + st = find_matching_stream(ts, pid, h->id, stream_identifier, i); } if (!st) { st = avformat_new_stream(ts->stream, NULL); @@ -2366,6 +2559,60 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len } } +static void eit_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) +{ + MpegTSContext *ts = filter->u.section_filter.opaque; + const uint8_t *p, *p_end; + SectionHeader h1, *h = &h1; + + /* + * Sometimes we receive EPG packets but SDT table do not have + * eit_pres_following or eit_sched turned on, so we open EPG + * stream directly here. + */ + if (!ts->epg_stream) { + ts->epg_stream = avformat_new_stream(ts->stream, NULL); + if (!ts->epg_stream) + return; + ts->epg_stream->id = EIT_PID; + ts->epg_stream->codecpar->codec_type = AVMEDIA_TYPE_DATA; + ts->epg_stream->codecpar->codec_id = AV_CODEC_ID_EPG; + } + + if (ts->epg_stream->discard == AVDISCARD_ALL) + return; + + p_end = section + section_len - 4; + p = section; + + if (parse_section_header(h, &p, p_end) < 0) + return; + if (h->tid < EIT_TID || h->tid > OEITS_END_TID) + return; + + av_log(ts->stream, AV_LOG_TRACE, "EIT: tid received = %.02x\n", h->tid); + + /** + * Service_id 0xFFFF is reserved, it indicates that the current EIT table + * is scrambled. + */ + if (h->id == 0xFFFF) { + av_log(ts->stream, AV_LOG_TRACE, "Scrambled EIT table received.\n"); + return; + } + + /** + * In case we receive an EPG packet before mpegts context is fully + * initialized. + */ + if (!ts->pkt) + return; + + new_data_packet(section, section_len, ts->pkt); + ts->pkt->stream_index = ts->epg_stream->index; + ts->stop_parse = 1; +} + static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { MpegTSContext *ts = filter->u.section_filter.opaque; @@ -2454,17 +2701,14 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, const uint8_t *packet); /* handle one TS packet */ -static int handle_packet(MpegTSContext *ts, const uint8_t *packet) +static int handle_packet(MpegTSContext *ts, const uint8_t *packet, int64_t pos) { MpegTSFilter *tss; int len, pid, cc, expected_cc, cc_ok, afc, is_start, is_discontinuity, has_adaptation, has_payload; const uint8_t *p, *p_end; - int64_t pos; pid = AV_RB16(packet + 1) & 0x1fff; - if (pid && discard_pid(ts, pid)) - return 0; is_start = packet[1] & 0x40; tss = ts->pids[pid]; if (ts->auto_guess && !tss && is_start) { @@ -2473,6 +2717,10 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) } if (!tss) return 0; + if (is_start) + tss->discard = discard_pid(ts, pid); + if (tss->discard) + return 0; ts->current_pid = pid; afc = (packet[3] >> 4) & 3; @@ -2525,7 +2773,6 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) if (p >= p_end || !has_payload) return 0; - pos = avio_tell(ts->stream->pb); if (pos >= 0) { av_assert0(pos >= TS_PACKET_SIZE); ts->pos47_full = pos - TS_PACKET_SIZE; @@ -2592,63 +2839,39 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) return 0; } -static void reanalyze(MpegTSContext *ts) { - AVIOContext *pb = ts->stream->pb; - int64_t pos = avio_tell(pb); - if (pos < 0) - return; - pos -= ts->pos47_full; - if (pos == TS_PACKET_SIZE) { - ts->size_stat[0] ++; - } else if (pos == TS_DVHS_PACKET_SIZE) { - ts->size_stat[1] ++; - } else if (pos == TS_FEC_PACKET_SIZE) { - ts->size_stat[2] ++; - } - - ts->size_stat_count ++; - if (ts->size_stat_count > SIZE_STAT_THRESHOLD) { - int newsize = 0; - if (ts->size_stat[0] > SIZE_STAT_THRESHOLD) { - newsize = TS_PACKET_SIZE; - } else if (ts->size_stat[1] > SIZE_STAT_THRESHOLD) { - newsize = TS_DVHS_PACKET_SIZE; - } else if (ts->size_stat[2] > SIZE_STAT_THRESHOLD) { - newsize = TS_FEC_PACKET_SIZE; - } - if (newsize && newsize != ts->raw_packet_size) { - av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", newsize); - ts->raw_packet_size = newsize; - } - ts->size_stat_count = 0; - memset(ts->size_stat, 0, sizeof(ts->size_stat)); - } -} - -/* XXX: try to find a better synchro over several packets (use - * get_packet_size() ?) */ static int mpegts_resync(AVFormatContext *s, int seekback, const uint8_t *current_packet) { MpegTSContext *ts = s->priv_data; AVIOContext *pb = s->pb; int c, i; uint64_t pos = avio_tell(pb); - - avio_seek(pb, -FFMIN(seekback, pos), SEEK_CUR); + int64_t back = FFMIN(seekback, pos); //Special case for files like 01c56b0dc1.ts if (current_packet[0] == 0x80 && current_packet[12] == 0x47) { - avio_seek(pb, 12, SEEK_CUR); + avio_seek(pb, 12 - back, SEEK_CUR); return 0; } + avio_seek(pb, -back, SEEK_CUR); + for (i = 0; i < ts->resync_size; i++) { c = avio_r8(pb); if (avio_feof(pb)) return AVERROR_EOF; if (c == 0x47) { + int new_packet_size, ret; avio_seek(pb, -1, SEEK_CUR); - reanalyze(s->priv_data); + pos = avio_tell(pb); + ret = ffio_ensure_seekback(pb, PROBE_PACKET_MAX_BUF); + if (ret < 0) + return ret; + new_packet_size = get_packet_size(s); + if (new_packet_size > 0 && new_packet_size != ts->raw_packet_size) { + av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", new_packet_size); + ts->raw_packet_size = new_packet_size; + } + avio_seek(pb, pos, SEEK_SET); return 0; } } @@ -2736,7 +2959,7 @@ static int handle_packets(MpegTSContext *ts, int64_t nb_packets) ret = read_packet(s, packet, ts->raw_packet_size, &data); if (ret != 0) break; - ret = handle_packet(ts, data); + ret = handle_packet(ts, data, avio_tell(s->pb)); finished_reading_packet(s, ts->raw_packet_size); if (ret != 0) break; @@ -2745,7 +2968,7 @@ static int handle_packets(MpegTSContext *ts, int64_t nb_packets) return ret; } -static int mpegts_probe(AVProbeData *p) +static int mpegts_probe(const AVProbeData *p) { const int size = p->buf_size; int maxscore = 0; @@ -2827,8 +3050,6 @@ static int mpegts_read_header(AVFormatContext *s) { MpegTSContext *ts = s->priv_data; AVIOContext *pb = s->pb; - uint8_t buf[8 * 1024] = {0}; - int len; int64_t pos, probesize = s->probesize; s->internal->prefer_codec_framerate = 1; @@ -2836,10 +3057,8 @@ static int mpegts_read_header(AVFormatContext *s) if (ffio_ensure_seekback(pb, probesize) < 0) av_log(s, AV_LOG_WARNING, "Failed to allocate buffers for seekback\n"); - /* read the first 8192 bytes to get packet size */ pos = avio_tell(pb); - len = avio_read(pb, buf, sizeof(buf)); - ts->raw_packet_size = get_packet_size(buf, len); + ts->raw_packet_size = get_packet_size(s); 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; @@ -2854,8 +3073,8 @@ static int mpegts_read_header(AVFormatContext *s) seek_back(s, pb, pos); mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); - mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1); + mpegts_open_section_filter(ts, EIT_PID, eit_cb, ts, 1); handle_packets(ts, probesize / ts->raw_packet_size); /* if could not find service, enable auto_guess */ @@ -2941,12 +3160,11 @@ static int mpegts_raw_read_packet(AVFormatContext *s, AVPacket *pkt) uint8_t pcr_buf[12]; const uint8_t *data; - if (av_new_packet(pkt, TS_PACKET_SIZE) < 0) - return AVERROR(ENOMEM); + if ((ret = av_new_packet(pkt, TS_PACKET_SIZE)) < 0) + return ret; ret = read_packet(s, pkt->data, ts->raw_packet_size, &data); pkt->pos = avio_tell(s->pb); if (ret < 0) { - av_packet_unref(pkt); return ret; } if (data != pkt->data) @@ -3016,6 +3234,9 @@ static void mpegts_free(MpegTSContext *ts) clear_programs(ts); + for (i = 0; i < FF_ARRAY_ELEMS(ts->pools); i++) + av_buffer_pool_uninit(&ts->pools[i]); + for (i = 0; i < NB_PID_MAX; i++) if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]); @@ -3110,8 +3331,10 @@ MpegTSContext *avpriv_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); + mpegts_open_section_filter(ts, EIT_PID, eit_cb, ts, 1); return ts; } @@ -3133,7 +3356,7 @@ int avpriv_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, buf++; len--; } else { - handle_packet(ts, buf); + handle_packet(ts, buf, len1 - len + TS_PACKET_SIZE); buf += TS_PACKET_SIZE; len -= TS_PACKET_SIZE; if (ts->stop_parse == 1)