X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmpegts.c;h=e8d82ac21c5b29893f388899acdf6b22b5eaa0d7;hb=d42b09723ed154d5269b95efcc20cb1874f60816;hp=a6e87c19cf43d909d4b0afc30bc8a700f361c793;hpb=40b0872a56d2177de8d305bf4f3fa34255b723aa;p=ffmpeg diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index a6e87c19cf4..e8d82ac21c5 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -21,6 +21,7 @@ //#define DEBUG //#define DEBUG_SEEK +//#define USE_SYNCPOINT_SEARCH #include "libavutil/crc.h" #include "libavutil/intreadwrite.h" @@ -28,22 +29,16 @@ #include "avformat.h" #include "mpegts.h" #include "internal.h" - -/* 1.0 second at 24Mbit/s */ -#define MAX_SCAN_PACKETS 32000 +#include "seek.h" +#include "mpeg.h" +#include "isom.h" /* maximum size in which we look for synchronisation if synchronisation is lost */ -#define MAX_RESYNC_SIZE 4096 -#define REGISTRATION_DESCRIPTOR 5 +#define MAX_RESYNC_SIZE 65536 #define MAX_PES_PAYLOAD 200*1024 -typedef struct PESContext PESContext; - -static PESContext* add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid, int stream_type); -static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code); - enum MpegTSFilterType { MPEGTS_PES, MPEGTS_SECTION, @@ -130,34 +125,38 @@ struct MpegTSContext { enum MpegTSState { MPEGTS_HEADER = 0, + MPEGTS_PESHEADER, MPEGTS_PESHEADER_FILL, MPEGTS_PAYLOAD, MPEGTS_SKIP, }; /* enough for PES header + length */ -#define PES_START_SIZE 9 +#define PES_START_SIZE 6 +#define PES_HEADER_SIZE 9 #define MAX_PES_HEADER_SIZE (9 + 255) -struct PESContext { +typedef struct PESContext { int pid; int pcr_pid; /**< if -1 then all packets containing PCR are considered */ int stream_type; MpegTSContext *ts; AVFormatContext *stream; AVStream *st; + AVStream *sub_st; /**< stream for the embedded AC3 stream in HDMV TrueHD */ enum MpegTSState state; /* used to get the format */ int data_index; int total_size; int pes_header_size; + int extended_stream_id; int64_t pts, dts; int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */ uint8_t header[MAX_PES_HEADER_SIZE]; uint8_t *buffer; -}; +} PESContext; -extern AVInputFormat mpegts_demuxer; +extern AVInputFormat ff_mpegts_demuxer; static void clear_program(MpegTSContext *ts, unsigned int programid) { @@ -239,7 +238,7 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid) } /** - * Assembles PES packets out of TS packets, and then calls the "section_cb" + * Assemble PES packets out of TS packets, and then call the "section_cb" * function when they are complete. */ static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1, @@ -288,7 +287,7 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int MpegTSFilter *filter; MpegTSSectionFilter *sec; - dprintf(ts->stream, "Filter: pid=0x%x\n", pid); + av_dlog(ts->stream, "Filter: pid=0x%x\n", pid); if (pid >= NB_PID_MAX || ts->pids[pid]) return NULL; @@ -355,7 +354,7 @@ static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter) } static int analyze(const uint8_t *buf, int size, int packet_size, int *index){ - int stat[packet_size]; + int stat[TS_MAX_PACKET_SIZE]; int i; int x=0; int best_score=0; @@ -484,6 +483,491 @@ static int parse_section_header(SectionHeader *h, return 0; } +typedef struct { + uint32_t stream_type; + enum AVMediaType codec_type; + enum CodecID codec_id; +} StreamType; + +static const StreamType ISO_types[] = { + { 0x01, AVMEDIA_TYPE_VIDEO, CODEC_ID_MPEG2VIDEO }, + { 0x02, AVMEDIA_TYPE_VIDEO, CODEC_ID_MPEG2VIDEO }, + { 0x03, AVMEDIA_TYPE_AUDIO, CODEC_ID_MP3 }, + { 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 */ + { 0x1b, AVMEDIA_TYPE_VIDEO, CODEC_ID_H264 }, + { 0xd1, AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC }, + { 0xea, AVMEDIA_TYPE_VIDEO, CODEC_ID_VC1 }, + { 0 }, +}; + +static const StreamType HDMV_types[] = { + { 0x80, AVMEDIA_TYPE_AUDIO, CODEC_ID_PCM_BLURAY }, + { 0x81, AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 }, + { 0x82, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, + { 0x83, AVMEDIA_TYPE_AUDIO, CODEC_ID_TRUEHD }, + { 0x84, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 }, + { 0x90, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_HDMV_PGS_SUBTITLE }, + { 0 }, +}; + +/* ATSC ? */ +static const StreamType MISC_types[] = { + { 0x81, AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 }, + { 0x8a, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, + { 0 }, +}; + +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 }, + { 0 }, +}; + +/* descriptor present */ +static const StreamType DESC_types[] = { + { 0x6a, AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 }, /* AC-3 descriptor */ + { 0x7a, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 }, /* E-AC-3 descriptor */ + { 0x7b, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, + { 0x56, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_DVB_TELETEXT }, + { 0x59, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_DVB_SUBTITLE }, /* subtitling descriptor */ + { 0 }, +}; + +static void mpegts_find_stream_type(AVStream *st, + uint32_t stream_type, const StreamType *types) +{ + for (; types->stream_type; types++) { + if (stream_type == types->stream_type) { + st->codec->codec_type = types->codec_type; + st->codec->codec_id = types->codec_id; + return; + } + } +} + +static int mpegts_set_stream_info(AVStream *st, PESContext *pes, + uint32_t stream_type, uint32_t prog_reg_desc) +{ + av_set_pts_info(st, 33, 1, 90000); + st->priv_data = pes; + st->codec->codec_type = AVMEDIA_TYPE_DATA; + st->codec->codec_id = CODEC_ID_NONE; + st->need_parsing = AVSTREAM_PARSE_FULL; + pes->st = st; + pes->stream_type = stream_type; + + av_log(pes->stream, AV_LOG_DEBUG, + "stream=%d stream_type=%x pid=%x prog_reg_desc=%.4s\n", + st->index, pes->stream_type, pes->pid, (char*)&prog_reg_desc); + + st->codec->codec_tag = pes->stream_type; + + mpegts_find_stream_type(st, pes->stream_type, ISO_types); + if (prog_reg_desc == AV_RL32("HDMV") && + st->codec->codec_id == CODEC_ID_NONE) { + mpegts_find_stream_type(st, pes->stream_type, HDMV_types); + if (pes->stream_type == 0x83) { + // HDMV TrueHD streams also contain an AC3 coded version of the + // audio track - add a second stream for this + AVStream *sub_st; + // priv_data cannot be shared between streams + PESContext *sub_pes = av_malloc(sizeof(*sub_pes)); + if (!sub_pes) + return AVERROR(ENOMEM); + memcpy(sub_pes, pes, sizeof(*sub_pes)); + + sub_st = av_new_stream(pes->stream, pes->pid); + if (!sub_st) { + av_free(sub_pes); + return AVERROR(ENOMEM); + } + + av_set_pts_info(sub_st, 33, 1, 90000); + sub_st->priv_data = sub_pes; + sub_st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + sub_st->codec->codec_id = CODEC_ID_AC3; + sub_st->need_parsing = AVSTREAM_PARSE_FULL; + sub_pes->sub_st = pes->sub_st = sub_st; + } + } + if (st->codec->codec_id == CODEC_ID_NONE) + mpegts_find_stream_type(st, pes->stream_type, MISC_types); + + return 0; +} + +static void new_pes_packet(PESContext *pes, AVPacket *pkt) +{ + av_init_packet(pkt); + + pkt->destruct = av_destruct_packet; + pkt->data = pes->buffer; + pkt->size = pes->data_index; + memset(pkt->data+pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + + // Separate out the AC3 substream from an HDMV combined TrueHD/AC3 PID + if (pes->sub_st && pes->stream_type == 0x83 && pes->extended_stream_id == 0x76) + pkt->stream_index = pes->sub_st->index; + else + pkt->stream_index = pes->st->index; + pkt->pts = pes->pts; + pkt->dts = pes->dts; + /* store position of first TS packet of this PES packet */ + pkt->pos = pes->ts_packet_pos; + + /* reset pts values */ + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + pes->buffer = NULL; + pes->data_index = 0; +} + +/* 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, + int64_t pos) +{ + PESContext *pes = filter->u.pes_filter.opaque; + MpegTSContext *ts = pes->ts; + const uint8_t *p; + int len, code; + + if(!ts->pkt) + return 0; + + if (is_start) { + if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { + new_pes_packet(pes, ts->pkt); + ts->stop_parse = 1; + } + pes->state = MPEGTS_HEADER; + pes->data_index = 0; + pes->ts_packet_pos = pos; + } + p = buf; + while (buf_size > 0) { + switch(pes->state) { + case MPEGTS_HEADER: + len = PES_START_SIZE - pes->data_index; + if (len > buf_size) + len = buf_size; + memcpy(pes->header + pes->data_index, p, len); + pes->data_index += len; + p += len; + buf_size -= len; + if (pes->data_index == PES_START_SIZE) { + /* we got all the PES or section header. We can now + decide */ +#if 0 + 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) { + /* it must be an mpeg2 PES stream */ + code = pes->header[3] | 0x100; + av_dlog(pes->stream, "pid=%x pes_code=%#x\n", pes->pid, code); + + if ((pes->st && pes->st->discard == AVDISCARD_ALL) || + code == 0x1be) /* padding_stream */ + goto skip; + +#if FF_API_MAX_STREAMS + if (!pes->st && pes->stream->nb_streams == MAX_STREAMS) + goto skip; +#endif + + /* stream not present in PMT */ + if (!pes->st) { + pes->st = av_new_stream(ts->stream, pes->pid); + if (!pes->st) + return AVERROR(ENOMEM); + mpegts_set_stream_info(pes->st, pes, 0, 0); + } + + pes->total_size = AV_RB16(pes->header + 4); + /* NOTE: a zero total size means the PES size is + unbounded */ + if (!pes->total_size) + pes->total_size = MAX_PES_PAYLOAD; + + /* allocate pes buffer */ + pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE); + if (!pes->buffer) + return AVERROR(ENOMEM); + + if (code != 0x1bc && code != 0x1bf && /* program_stream_map, private_stream_2 */ + code != 0x1f0 && code != 0x1f1 && /* ECM, EMM */ + 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) { + av_dlog(pes->stream, "pid=%x stream_type=%x probing\n", + pes->pid, pes->stream_type); + pes->st->codec->codec_id = CODEC_ID_PROBE; + } + } else { + pes->state = MPEGTS_PAYLOAD; + pes->data_index = 0; + } + } else { + /* otherwise, it should be a table */ + /* skip packet */ + skip: + pes->state = MPEGTS_SKIP; + continue; + } + } + break; + /**********************************************/ + /* PES packing parsing */ + case MPEGTS_PESHEADER: + len = PES_HEADER_SIZE - pes->data_index; + if (len < 0) + return -1; + if (len > buf_size) + len = buf_size; + memcpy(pes->header + pes->data_index, p, len); + pes->data_index += len; + p += len; + buf_size -= len; + if (pes->data_index == PES_HEADER_SIZE) { + pes->pes_header_size = pes->header[8] + 9; + pes->state = MPEGTS_PESHEADER_FILL; + } + break; + case MPEGTS_PESHEADER_FILL: + len = pes->pes_header_size - pes->data_index; + if (len < 0) + return -1; + if (len > buf_size) + len = buf_size; + memcpy(pes->header + pes->data_index, p, len); + pes->data_index += len; + p += len; + buf_size -= len; + if (pes->data_index == pes->pes_header_size) { + const uint8_t *r; + unsigned int flags, pes_ext, skip; + + flags = pes->header[7]; + r = pes->header + 9; + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + if ((flags & 0xc0) == 0x80) { + pes->dts = pes->pts = ff_parse_pes_pts(r); + r += 5; + } else if ((flags & 0xc0) == 0xc0) { + pes->pts = ff_parse_pes_pts(r); + r += 5; + pes->dts = ff_parse_pes_pts(r); + r += 5; + } + pes->extended_stream_id = -1; + if (flags & 0x01) { /* PES extension */ + pes_ext = *r++; + /* Skip PES private data, program packet sequence counter and P-STD buffer */ + skip = (pes_ext >> 4) & 0xb; + skip += skip & 0x9; + r += skip; + if ((pes_ext & 0x41) == 0x01 && + (r + 2) <= (pes->header + pes->pes_header_size)) { + /* PES extension 2 */ + if ((r[0] & 0x7f) > 0 && (r[1] & 0x80) == 0) + pes->extended_stream_id = r[1]; + } + } + + /* we got the full header. We parse it and get the payload */ + pes->state = MPEGTS_PAYLOAD; + pes->data_index = 0; + } + break; + case MPEGTS_PAYLOAD: + if (buf_size > 0 && pes->buffer) { + if (pes->data_index > 0 && pes->data_index+buf_size > pes->total_size) { + new_pes_packet(pes, ts->pkt); + pes->total_size = MAX_PES_PAYLOAD; + pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE); + if (!pes->buffer) + return AVERROR(ENOMEM); + ts->stop_parse = 1; + } else if (pes->data_index == 0 && buf_size > pes->total_size) { + // pes packet size is < ts size packet and pes data is padded with 0xff + // not sure if this is legal in ts but see issue #2392 + buf_size = pes->total_size; + } + memcpy(pes->buffer+pes->data_index, p, buf_size); + pes->data_index += buf_size; + } + buf_size = 0; + /* emit complete packets with known packet size + * decreases demuxer delay for infrequent packets like subtitles from + * a couple of seconds to milliseconds for properly muxed files. + * total_size is the number of bytes following pes_packet_length + * in the pes header, i.e. not counting the first 6 bytes */ + if (pes->total_size < MAX_PES_PAYLOAD && + pes->pes_header_size + pes->data_index == pes->total_size + 6) { + ts->stop_parse = 1; + new_pes_packet(pes, ts->pkt); + } + break; + case MPEGTS_SKIP: + buf_size = 0; + break; + } + } + + return 0; +} + +static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid) +{ + MpegTSFilter *tss; + PESContext *pes; + + /* if no pid found, then add a pid context */ + pes = av_mallocz(sizeof(PESContext)); + if (!pes) + return 0; + pes->ts = ts; + pes->stream = ts->stream; + pes->pid = pid; + pes->pcr_pid = pcr_pid; + pes->state = MPEGTS_SKIP; + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); + if (!tss) { + av_free(pes); + return 0; + } + return pes; +} + +static int mp4_read_iods(AVFormatContext *s, const uint8_t *buf, unsigned size, + int *es_id, uint8_t **dec_config_descr, + int *dec_config_descr_size) +{ + ByteIOContext pb; + int tag; + unsigned len; + + init_put_byte(&pb, buf, size, 0, NULL, NULL, NULL, NULL); + + len = ff_mp4_read_descr(s, &pb, &tag); + if (tag == MP4IODescrTag) { + get_be16(&pb); // ID + get_byte(&pb); + get_byte(&pb); + get_byte(&pb); + get_byte(&pb); + get_byte(&pb); + len = ff_mp4_read_descr(s, &pb, &tag); + if (tag == MP4ESDescrTag) { + *es_id = get_be16(&pb); /* ES_ID */ + av_dlog(s, "ES_ID %#x\n", *es_id); + get_byte(&pb); /* priority */ + len = ff_mp4_read_descr(s, &pb, &tag); + if (tag == MP4DecConfigDescrTag) { + *dec_config_descr = av_malloc(len); + if (!*dec_config_descr) + return AVERROR(ENOMEM); + *dec_config_descr_size = len; + get_buffer(&pb, *dec_config_descr, len); + } + } + } + return 0; +} + +int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type, + const uint8_t **pp, const uint8_t *desc_list_end, + int mp4_dec_config_descr_len, int mp4_es_id, int pid, + uint8_t *mp4_dec_config_descr) +{ + const uint8_t *desc_end; + int desc_len, desc_tag; + char language[4]; + + desc_tag = get8(pp, desc_list_end); + if (desc_tag < 0) + return -1; + desc_len = get8(pp, desc_list_end); + if (desc_len < 0) + return -1; + desc_end = *pp + desc_len; + if (desc_end > desc_list_end) + return -1; + + av_dlog(fc, "tag: 0x%02x len=%d\n", desc_tag, desc_len); + + if (st->codec->codec_id == CODEC_ID_NONE && + stream_type == STREAM_TYPE_PRIVATE_DATA) + mpegts_find_stream_type(st, desc_tag, DESC_types); + + switch(desc_tag) { + case 0x1F: /* FMC descriptor */ + get16(pp, desc_end); + if (st->codec->codec_id == CODEC_ID_AAC_LATM && + mp4_dec_config_descr_len && mp4_es_id == pid) { + ByteIOContext pb; + init_put_byte(&pb, mp4_dec_config_descr, + mp4_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; + } + break; + case 0x56: /* DVB teletext descriptor */ + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + av_metadata_set2(&st->metadata, "language", language, 0); + break; + case 0x59: /* subtitling descriptor */ + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + get8(pp, desc_end); + if (st->codec->extradata) { + if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, *pp, 4)) + av_log_ask_for_sample(fc, "DVB sub with multiple IDs\n"); + } else { + st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE); + if (st->codec->extradata) { + st->codec->extradata_size = 4; + memcpy(st->codec->extradata, *pp, 4); + } + } + *pp += 4; + av_metadata_set2(&st->metadata, "language", language, 0); + break; + case 0x0a: /* ISO 639 language descriptor */ + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + av_metadata_set2(&st->metadata, "language", language, 0); + break; + case 0x05: /* registration descriptor */ + st->codec->codec_tag = bytestream_get_le32(pp); + av_dlog(fc, "reg_desc=%.4s\n", (char*)&st->codec->codec_tag); + if (st->codec->codec_id == CODEC_ID_NONE && + stream_type == STREAM_TYPE_PRIVATE_DATA) + mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types); + break; + default: + break; + } + *pp = desc_end; + return 0; +} static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { @@ -491,17 +975,16 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len SectionHeader h1, *h = &h1; PESContext *pes; AVStream *st; - const uint8_t *p, *p_end, *desc_list_end, *desc_end; + const uint8_t *p, *p_end, *desc_list_end; int program_info_length, pcr_pid, pid, stream_type; - int desc_list_len, desc_len, desc_tag; - int comp_page = 0, anc_page = 0; /* initialize to kill warnings */ - char language[4] = {0}; /* initialize to kill warnings */ - int has_hdmv_descr = 0; - int has_dirac_descr = 0; - uint32_t reg_desc = 0; /* registration descriptor */ + int desc_list_len; + uint32_t prog_reg_desc = 0; /* registration descriptor */ + uint8_t *mp4_dec_config_descr = NULL; + int mp4_dec_config_descr_len = 0; + int mp4_es_id = 0; #ifdef DEBUG - dprintf(ts->stream, "PMT: len %i\n", section_len); + av_dlog(ts->stream, "PMT: len %i\n", section_len); av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len); #endif @@ -510,7 +993,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (parse_section_header(h, &p, p_end) < 0) return; - dprintf(ts->stream, "sid=0x%x sec_num=%d/%d\n", + av_dlog(ts->stream, "sid=0x%x sec_num=%d/%d\n", h->id, h->sec_num, h->last_sec_num); if (h->tid != PMT_TID) @@ -522,7 +1005,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len return; add_pid_to_pmt(ts, h->id, pcr_pid); - dprintf(ts->stream, "pcr_pid=0x%x\n", pcr_pid); + av_dlog(ts->stream, "pcr_pid=0x%x\n", pcr_pid); program_info_length = get16(&p, p_end) & 0xfff; if (program_info_length < 0) @@ -531,23 +1014,34 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len uint8_t tag, len; tag = get8(&p, p_end); len = get8(&p, p_end); + + av_dlog(ts->stream, "program tag: 0x%02x len=%d\n", tag, len); + if(len > program_info_length - 2) //something else is broken, exit the program_descriptors_loop break; program_info_length -= len + 2; - if(tag == REGISTRATION_DESCRIPTOR && len >= 4) { - reg_desc = bytestream_get_le32(&p); + if (tag == 0x1d) { // IOD descriptor + get8(&p, p_end); // scope + get8(&p, p_end); // label + len -= 2; + mp4_read_iods(ts->stream, p, len, &mp4_es_id, + &mp4_dec_config_descr, &mp4_dec_config_descr_len); + } else if (tag == 0x05 && len >= 4) { // registration descriptor + prog_reg_desc = bytestream_get_le32(&p); len -= 4; - if(reg_desc == AV_RL32("HDMV")) - has_hdmv_descr = 1; } p += len; } p += program_info_length; if (p >= p_end) - return; + goto out; + + // stop parsing after pmt, we found header + if (!ts->stream->nb_streams) + ts->stop_parse = 1; + for(;;) { - language[0] = 0; st = 0; stream_type = get8(&p, p_end); if (stream_type < 0) @@ -555,98 +1049,51 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len pid = get16(&p, p_end) & 0x1fff; if (pid < 0) break; - desc_list_len = get16(&p, p_end) & 0xfff; - if (desc_list_len < 0) - break; - desc_list_end = p + desc_list_len; - if (desc_list_end > p_end) - break; - for(;;) { - 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); - if (desc_len < 0) - break; - desc_end = p + desc_len; - if (desc_end > desc_list_end) - break; - - dprintf(ts->stream, "tag: 0x%02x len=%d\n", - desc_tag, desc_len); - - switch(desc_tag) { - case DVB_SUBT_DESCID: - if (stream_type == STREAM_TYPE_PRIVATE_DATA) - stream_type = STREAM_TYPE_SUBTITLE_DVB; - - language[0] = get8(&p, desc_end); - language[1] = get8(&p, desc_end); - language[2] = get8(&p, desc_end); - language[3] = 0; - get8(&p, desc_end); - comp_page = get16(&p, desc_end); - anc_page = get16(&p, desc_end); - - break; - case 0x0a: /* ISO 639 language descriptor */ - language[0] = get8(&p, desc_end); - language[1] = get8(&p, desc_end); - language[2] = get8(&p, desc_end); - language[3] = 0; - break; - case REGISTRATION_DESCRIPTOR: /*MPEG-2 Registration descriptor */ - reg_desc = bytestream_get_le32(&p); - if(reg_desc == AV_RL32("drac")) - has_dirac_descr = 1; - else if(reg_desc == AV_RL32("AC-3")) - stream_type = STREAM_TYPE_AUDIO_AC3; - break; - default: - break; - } - p = desc_end; - } - p = desc_list_end; - - dprintf(ts->stream, "stream_type=%x pid=0x%x\n", - stream_type, pid); /* now create ffmpeg stream */ if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { - pes= ts->pids[pid]->u.pes_filter.opaque; - st= pes->st; + pes = ts->pids[pid]->u.pes_filter.opaque; + if (!pes->st) + pes->st = av_new_stream(pes->stream, pes->pid); + st = pes->st; } else { if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably - pes = add_pes_stream(ts, pid, pcr_pid, stream_type); + pes = add_pes_stream(ts, pid, pcr_pid); if (pes) - st = new_pes_av_stream(pes, 0); + st = av_new_stream(pes->stream, pes->pid); } + if (!st) + goto out; + + if (!pes->stream_type) + mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc); + add_pid_to_pmt(ts, h->id, pid); - if(st) { - av_program_add_stream_index(ts->stream, h->id, st->index); + ff_program_add_stream_index(ts->stream, h->id, st->index); - if (language[0] != 0) - av_metadata_set(&st->metadata, "language", language); + desc_list_len = get16(&p, p_end) & 0xfff; + if (desc_list_len < 0) + break; + desc_list_end = p + desc_list_len; + if (desc_list_end > p_end) + break; + for(;;) { + if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, desc_list_end, + mp4_dec_config_descr_len, mp4_es_id, pid, mp4_dec_config_descr) < 0) + break; - if (stream_type == STREAM_TYPE_SUBTITLE_DVB) - st->codec->sub_id = (anc_page << 16) | comp_page; + if (prog_reg_desc == AV_RL32("HDMV") && stream_type == 0x83 && pes->sub_st) { + ff_program_add_stream_index(ts->stream, h->id, pes->sub_st->index); + pes->sub_st->codec->codec_tag = st->codec->codec_tag; + } } + p = desc_list_end; } - /* all parameters are there */ - ts->stop_parse++; - mpegts_close_filter(ts, filter); + + out: + av_free(mp4_dec_config_descr); } static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) @@ -657,7 +1104,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len int sid, pmt_pid; #ifdef DEBUG - dprintf(ts->stream, "PAT:\n"); + av_dlog(ts->stream, "PAT:\n"); av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len); #endif p_end = section + section_len - 4; @@ -676,23 +1123,20 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (pmt_pid < 0) break; - dprintf(ts->stream, "sid=0x%x pid=0x%x\n", sid, pmt_pid); + av_dlog(ts->stream, "sid=0x%x pid=0x%x\n", sid, pmt_pid); if (sid == 0x0000) { /* NIT info */ } else { av_new_program(ts->stream, sid); - ts->stop_parse--; + if (ts->pids[pmt_pid]) + mpegts_close_filter(ts, ts->pids[pmt_pid]); mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); add_pat_entry(ts, sid); add_pid_to_pmt(ts, sid, 0); //add pat pid to program add_pid_to_pmt(ts, sid, pmt_pid); } } - /* not found */ - ts->stop_parse++; - - mpegts_close_filter(ts, filter); } static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) @@ -704,7 +1148,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len char *name, *provider_name; #ifdef DEBUG - dprintf(ts->stream, "SDT:\n"); + av_dlog(ts->stream, "SDT:\n"); av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len); #endif @@ -742,7 +1186,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (desc_end > desc_list_end) break; - dprintf(ts->stream, "tag: 0x%02x len=%d\n", + av_dlog(ts->stream, "tag: 0x%02x len=%d\n", desc_tag, desc_len); switch(desc_tag) { @@ -757,8 +1201,8 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (name) { AVProgram *program = av_new_program(ts->stream, sid); if(program) { - av_metadata_set(&program->metadata, "name", name); - av_metadata_set(&program->metadata, "provider_name", provider_name); + av_metadata_set2(&program->metadata, "service_name", name, 0); + av_metadata_set2(&program->metadata, "service_provider", provider_name, 0); } } av_free(name); @@ -773,264 +1217,6 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len } } -static int64_t get_pts(const uint8_t *p) -{ - int64_t pts = (int64_t)((p[0] >> 1) & 0x07) << 30; - pts |= (AV_RB16(p + 1) >> 1) << 15; - pts |= AV_RB16(p + 3) >> 1; - return pts; -} - -static void new_pes_packet(PESContext *pes, AVPacket *pkt) -{ - av_init_packet(pkt); - - pkt->destruct = av_destruct_packet; - pkt->data = pes->buffer; - pkt->size = pes->data_index; - memset(pkt->data+pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); - - pkt->stream_index = pes->st->index; - pkt->pts = pes->pts; - pkt->dts = pes->dts; - /* store position of first TS packet of this PES packet */ - pkt->pos = pes->ts_packet_pos; - - /* reset pts values */ - pes->pts = AV_NOPTS_VALUE; - pes->dts = AV_NOPTS_VALUE; - pes->buffer = NULL; - pes->data_index = 0; -} - -/* 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, - int64_t pos) -{ - PESContext *pes = filter->u.pes_filter.opaque; - MpegTSContext *ts = pes->ts; - const uint8_t *p; - int len, code; - - if(!ts->pkt) - return 0; - - if (is_start) { - if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { - new_pes_packet(pes, ts->pkt); - ts->stop_parse = 1; - } - pes->state = MPEGTS_HEADER; - pes->data_index = 0; - pes->ts_packet_pos = pos; - } - p = buf; - while (buf_size > 0) { - switch(pes->state) { - case MPEGTS_HEADER: - len = PES_START_SIZE - pes->data_index; - if (len > buf_size) - len = buf_size; - memcpy(pes->header + pes->data_index, p, len); - pes->data_index += len; - p += len; - buf_size -= len; - if (pes->data_index == PES_START_SIZE) { - /* we got all the PES or section header. We can now - decide */ -#if 0 - 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) { - /* it must be an mpeg2 PES stream */ - code = pes->header[3] | 0x100; - if (!pes->st || pes->st->discard == AVDISCARD_ALL || - !((code >= 0x1c0 && code <= 0x1df) || - (code >= 0x1e0 && code <= 0x1ef) || - (code == 0x1bd) || (code == 0x1fd))) - goto skip; - pes->state = MPEGTS_PESHEADER_FILL; - pes->total_size = AV_RB16(pes->header + 4); - /* NOTE: a zero total size means the PES size is - unbounded */ - pes->pes_header_size = pes->header[8] + 9; - } else { - /* otherwise, it should be a table */ - /* skip packet */ - skip: - pes->state = MPEGTS_SKIP; - continue; - } - } - break; - /**********************************************/ - /* PES packing parsing */ - case MPEGTS_PESHEADER_FILL: - len = pes->pes_header_size - pes->data_index; - if (len < 0) - return -1; - if (len > buf_size) - len = buf_size; - memcpy(pes->header + pes->data_index, p, len); - pes->data_index += len; - p += len; - buf_size -= len; - if (pes->data_index == pes->pes_header_size) { - const uint8_t *r; - unsigned int flags; - - flags = pes->header[7]; - r = pes->header + 9; - pes->pts = AV_NOPTS_VALUE; - pes->dts = AV_NOPTS_VALUE; - if ((flags & 0xc0) == 0x80) { - pes->dts = pes->pts = get_pts(r); - r += 5; - } else if ((flags & 0xc0) == 0xc0) { - pes->pts = get_pts(r); - r += 5; - pes->dts = get_pts(r); - r += 5; - } - - if (pes->total_size > pes->data_index - 6) - pes->total_size -= pes->data_index - 6; - else - pes->total_size = MAX_PES_PAYLOAD; - /* allocate pes buffer */ - pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE); - if (!pes->buffer) - return AVERROR(ENOMEM); - - /* we got the full header. We parse it and get the payload */ - pes->state = MPEGTS_PAYLOAD; - pes->data_index = 0; - } - break; - case MPEGTS_PAYLOAD: - if (buf_size > 0) { - if (pes->data_index+buf_size > pes->total_size) { - new_pes_packet(pes, ts->pkt); - pes->total_size = MAX_PES_PAYLOAD; - pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE); - if (!pes->buffer) - return AVERROR(ENOMEM); - ts->stop_parse = 1; - } - memcpy(pes->buffer+pes->data_index, p, buf_size); - pes->data_index += buf_size; - } - buf_size = 0; - break; - case MPEGTS_SKIP: - buf_size = 0; - break; - } - } - - return 0; -} - -static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code) -{ - AVStream *st; - enum CodecID codec_id; - enum CodecType codec_type; - - switch(pes->stream_type){ - case STREAM_TYPE_AUDIO_MPEG1: - case STREAM_TYPE_AUDIO_MPEG2: - codec_type = CODEC_TYPE_AUDIO; - codec_id = CODEC_ID_MP3; - break; - case STREAM_TYPE_VIDEO_MPEG1: - case STREAM_TYPE_VIDEO_MPEG2: - codec_type = CODEC_TYPE_VIDEO; - codec_id = CODEC_ID_MPEG2VIDEO; - break; - case STREAM_TYPE_VIDEO_MPEG4: - codec_type = CODEC_TYPE_VIDEO; - codec_id = CODEC_ID_MPEG4; - break; - case STREAM_TYPE_VIDEO_H264: - 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_VIDEO_DIRAC: - codec_type = CODEC_TYPE_VIDEO; - codec_id = CODEC_ID_DIRAC; - break; - case STREAM_TYPE_AUDIO_AAC: - codec_type = CODEC_TYPE_AUDIO; - codec_id = CODEC_ID_AAC; - break; - case STREAM_TYPE_AUDIO_AC3: - codec_type = CODEC_TYPE_AUDIO; - codec_id = CODEC_ID_AC3; - break; - case STREAM_TYPE_AUDIO_DTS: - case STREAM_TYPE_AUDIO_HDMV_DTS: - codec_type = CODEC_TYPE_AUDIO; - codec_id = CODEC_ID_DTS; - break; - case STREAM_TYPE_SUBTITLE_DVB: - codec_type = CODEC_TYPE_SUBTITLE; - codec_id = CODEC_ID_DVB_SUBTITLE; - break; - default: - if (code >= 0x1c0 && code <= 0x1df) { - codec_type = CODEC_TYPE_AUDIO; - codec_id = CODEC_ID_MP2; - } else if (code == 0x1bd) { - codec_type = CODEC_TYPE_AUDIO; - codec_id = CODEC_ID_AC3; - } else { - codec_type = CODEC_TYPE_DATA; - codec_id = CODEC_ID_PROBE; - } - break; - } - st = av_new_stream(pes->stream, pes->pid); - if (st) { - av_set_pts_info(st, 33, 1, 90000); - st->priv_data = pes; - st->codec->codec_type = codec_type; - st->codec->codec_id = codec_id; - st->need_parsing = AVSTREAM_PARSE_FULL; - pes->st = st; - } - return st; -} - - -static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid, int stream_type) -{ - MpegTSFilter *tss; - PESContext *pes; - - /* if no pid found, then add a pid context */ - pes = av_mallocz(sizeof(PESContext)); - if (!pes) - return 0; - pes->ts = ts; - pes->stream = ts->stream; - pes->pid = pid; - pes->pcr_pid = pcr_pid; - pes->stream_type = stream_type; - tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); - if (!tss) { - av_free(pes); - return 0; - } - return pes; -} - /* handle one TS packet */ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) { @@ -1046,7 +1232,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) is_start = packet[1] & 0x40; tss = ts->pids[pid]; if (ts->auto_guess && tss == NULL && is_start) { - add_pes_stream(ts, pid, -1, 0); + add_pes_stream(ts, pid, -1); tss = ts->pids[pid]; } if (!tss) @@ -1114,8 +1300,9 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) /* XXX: try to find a better synchro over several packets (use get_packet_size() ?) */ -static int mpegts_resync(ByteIOContext *pb) +static int mpegts_resync(AVFormatContext *s) { + ByteIOContext *pb = s->pb; int c, i; for(i = 0;i < MAX_RESYNC_SIZE; i++) { @@ -1127,13 +1314,15 @@ static int mpegts_resync(ByteIOContext *pb) return 0; } } + av_log(s, AV_LOG_ERROR, "max resync size reached, could not find sync byte\n"); /* no sync found */ return -1; } /* return -1 if error or EOF. Return 0 if OK. */ -static int read_packet(ByteIOContext *pb, uint8_t *buf, int raw_packet_size) +static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size) { + ByteIOContext *pb = s->pb; int skip, len; for(;;) { @@ -1144,8 +1333,8 @@ static int read_packet(ByteIOContext *pb, uint8_t *buf, int raw_packet_size) if (buf[0] != 0x47) { /* find a new packet start */ url_fseek(pb, -TS_PACKET_SIZE, SEEK_CUR); - if (mpegts_resync(pb) < 0) - return AVERROR_INVALIDDATA; + if (mpegts_resync(s) < 0) + return AVERROR(EAGAIN); else continue; } else { @@ -1161,7 +1350,6 @@ static int read_packet(ByteIOContext *pb, uint8_t *buf, int raw_packet_size) static int handle_packets(MpegTSContext *ts, int nb_packets) { AVFormatContext *s = ts->stream; - ByteIOContext *pb = s->pb; uint8_t packet[TS_PACKET_SIZE]; int packet_num, ret; @@ -1173,7 +1361,7 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) packet_num++; if (nb_packets != 0 && packet_num >= nb_packets) break; - ret = read_packet(pb, packet, ts->raw_packet_size); + ret = read_packet(s, packet, ts->raw_packet_size); if (ret != 0) return ret; ret = handle_packet(ts, packet); @@ -1206,7 +1394,7 @@ static int mpegts_probe(AVProbeData *p) else return -1; #else /* only use the extension for safer guess */ - if (match_ext(p->filename, "ts")) + if (av_match_ext(p->filename, "ts")) return AVPROBE_SCORE_MAX; else return 0; @@ -1270,22 +1458,23 @@ static int mpegts_read_header(AVFormatContext *s, ts->stream = s; ts->auto_guess = 0; - if (s->iformat == &mpegts_demuxer) { + if (s->iformat == &ff_mpegts_demuxer) { /* normal demux */ /* first do a scaning to get all the services */ - url_fseek(pb, pos, SEEK_SET); + if (url_fseek(pb, pos, SEEK_SET) < 0) + av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n"); mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1); - handle_packets(ts, s->probesize); + handle_packets(ts, s->probesize / ts->raw_packet_size); /* if could not find service, enable auto_guess */ ts->auto_guess = 1; - dprintf(ts->stream, "tuning done\n"); + av_dlog(ts->stream, "tuning done\n"); s->ctx_flags |= AVFMTCTX_NOHEADER; } else { @@ -1301,7 +1490,7 @@ static int mpegts_read_header(AVFormatContext *s, if (!st) goto fail; av_set_pts_info(st, 60, 1, 27000000); - st->codec->codec_type = CODEC_TYPE_DATA; + st->codec->codec_type = AVMEDIA_TYPE_DATA; st->codec->codec_id = CODEC_ID_MPEG2TS; /* we iterate until we find two PCRs to estimate the bitrate */ @@ -1309,7 +1498,7 @@ static int mpegts_read_header(AVFormatContext *s, nb_pcrs = 0; nb_packets = 0; for(;;) { - ret = read_packet(s->pb, packet, ts->raw_packet_size); + ret = read_packet(s, packet, ts->raw_packet_size); if (ret < 0) return -1; pid = AV_RB16(packet + 1) & 0x1fff; @@ -1358,7 +1547,7 @@ static int mpegts_raw_read_packet(AVFormatContext *s, if (av_new_packet(pkt, TS_PACKET_SIZE) < 0) return AVERROR(ENOMEM); pkt->pos= url_ftell(s->pb); - ret = read_packet(s->pb, pkt->data, ts->raw_packet_size); + ret = read_packet(s, pkt->data, ts->raw_packet_size); if (ret < 0) { av_free_packet(pkt); return ret; @@ -1417,6 +1606,7 @@ static int mpegts_read_packet(AVFormatContext *s, PESContext *pes = ts->pids[i]->u.pes_filter.opaque; if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { new_pes_packet(pes, pkt); + pes->state = MPEGTS_SKIP; ret = 0; break; } @@ -1481,6 +1671,92 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, return timestamp; } +#ifdef USE_SYNCPOINT_SEARCH + +static int read_seek2(AVFormatContext *s, + int stream_index, + int64_t min_ts, + int64_t target_ts, + int64_t max_ts, + int flags) +{ + int64_t pos; + + int64_t ts_ret, ts_adj; + int stream_index_gen_search; + AVStream *st; + AVParserState *backup; + + backup = ff_store_parser_state(s); + + // detect direction of seeking for search purposes + flags |= (target_ts - min_ts > (uint64_t)(max_ts - target_ts)) ? + AVSEEK_FLAG_BACKWARD : 0; + + if (flags & AVSEEK_FLAG_BYTE) { + // use position directly, we will search starting from it + pos = target_ts; + } else { + // search for some position with good timestamp match + if (stream_index < 0) { + stream_index_gen_search = av_find_default_stream_index(s); + if (stream_index_gen_search < 0) { + ff_restore_parser_state(s, backup); + return -1; + } + + st = s->streams[stream_index_gen_search]; + // timestamp for default must be expressed in AV_TIME_BASE units + ts_adj = av_rescale(target_ts, + st->time_base.den, + AV_TIME_BASE * (int64_t)st->time_base.num); + } else { + ts_adj = target_ts; + stream_index_gen_search = stream_index; + } + pos = av_gen_search(s, stream_index_gen_search, ts_adj, + 0, INT64_MAX, -1, + AV_NOPTS_VALUE, + AV_NOPTS_VALUE, + flags, &ts_ret, mpegts_get_pcr); + if (pos < 0) { + ff_restore_parser_state(s, backup); + return -1; + } + } + + // search for actual matching keyframe/starting position for all streams + if (ff_gen_syncpoint_search(s, stream_index, pos, + min_ts, target_ts, max_ts, + flags) < 0) { + ff_restore_parser_state(s, backup); + return -1; + } + + ff_free_parser_state(s, backup); + return 0; +} + +static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags) +{ + int ret; + if (flags & AVSEEK_FLAG_BACKWARD) { + flags &= ~AVSEEK_FLAG_BACKWARD; + ret = read_seek2(s, stream_index, INT64_MIN, target_ts, target_ts, flags); + if (ret < 0) + // for compatibility reasons, seek to the best-fitting timestamp + ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags); + } else { + ret = read_seek2(s, stream_index, target_ts, target_ts, INT64_MAX, flags); + if (ret < 0) + // for compatibility reasons, seek to the best-fitting timestamp + ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags); + } + 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]; @@ -1504,10 +1780,12 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, in return 0; } +#endif + /**************************************************************/ /* parsing functions - called from other demuxers such as RTP */ -MpegTSContext *mpegts_parse_open(AVFormatContext *s) +MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s) { MpegTSContext *ts; @@ -1523,7 +1801,7 @@ MpegTSContext *mpegts_parse_open(AVFormatContext *s) /* return the consumed length if a packet was output, or -1 if no packet is output */ -int mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, +int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, const uint8_t *buf, int len) { int len1; @@ -1548,7 +1826,7 @@ int mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, return len1 - len; } -void mpegts_parse_close(MpegTSContext *ts) +void ff_mpegts_parse_close(MpegTSContext *ts) { int i; @@ -1557,7 +1835,7 @@ void mpegts_parse_close(MpegTSContext *ts) av_free(ts); } -AVInputFormat mpegts_demuxer = { +AVInputFormat ff_mpegts_demuxer = { "mpegts", NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"), sizeof(MpegTSContext), @@ -1568,9 +1846,12 @@ AVInputFormat mpegts_demuxer = { read_seek, mpegts_get_pcr, .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, +#ifdef USE_SYNCPOINT_SEARCH + .read_seek2 = read_seek2, +#endif }; -AVInputFormat mpegtsraw_demuxer = { +AVInputFormat ff_mpegtsraw_demuxer = { "mpegtsraw", NULL_IF_CONFIG_SMALL("MPEG-2 raw transport stream format"), sizeof(MpegTSContext), @@ -1581,4 +1862,7 @@ AVInputFormat mpegtsraw_demuxer = { read_seek, mpegts_get_pcr, .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, +#ifdef USE_SYNCPOINT_SEARCH + .read_seek2 = read_seek2, +#endif };