On Tue, May 15, 2018, 15:12 Michael Niedermayer <mich...@niedermayer.cc> wrote:
> On Mon, May 14, 2018 at 03:54:01PM -0700, Aman Gupta wrote: > > From: Aman Gupta <a...@tmm1.net> > > > > This new optional flag makes it easier to deal with mpegts > > samples where the PMT is updated and elementary streams move > > to different PIDs in the middle of playback. > > > > Previously, new AVStreams were created per PID, and it was up > > to the user to figure out which streams had migrated to a new PID > > (by iterating over the list of AVProgram and making guesses), and > > switch seamlessly to the new AVStream during playback. > > > > Transcoding or remuxing these streams with ffmpeg on the CLI was > > also quite painful, and the user would need to extract each set of > > PIDs into a separate file and then stitch them back together. > > > > With this new option, the mpegts demuxer will automatically detect > > PMT changes and feed data from the new PID to the original AVStream > > that was created for the orignal PID. For mpegts samples with > > stream_identifier_descriptor available, the unique ID is used to merge > > PIDs together. If the stream id is not available, the demuxer attempts > > to map PIDs based on their order and relation to the PCR pid. > > > > With this change, I am able to playback and transcode/remux these > > two samples which previously caused issues: > > > > https://tmm1.s3.amazonaws.com/pmt-version-change.ts > > https://kuroko.fushizen.eu/videos/pid_switch_sample.ts > > > > I also have another longer sample which contains multiple PMT > > changes, some of which change the ES pids and others which do not: > > > > https://tmm1.s3.amazonaws.com/multiple-pmt-change.ts > > > > Demuxing this sample with the new option shows several new log > > messages as the PMT changes are handled: > > > > [mpegts @ 0x7ffe18801200] detected PMT change (version=3/4, > pcr_pid=0xf98/0xf9b) > > [mpegts @ 0x7ffe18801200] re-using existing video stream 0 > (pid=0xf98) for new pid=0xf9b > > [mpegts @ 0x7ffe18801200] re-using existing audio stream 1 > (pid=0xf99) for new pid=0xf9c > > [mpegts @ 0x7ffe18801200] re-using existing audio stream 2 > (pid=0xf9a) for new pid=0xf9d > > [mpegts @ 0x7ffe18801200] detected PMT change (version=4/5, > pcr_pid=0xf9b/0xfa9) > > [mpegts @ 0x7ffe18801200] re-using existing video stream 0 > (pid=0xf98) for new pid=0xfa9 > > [mpegts @ 0x7ffe18801200] re-using existing audio stream 1 > (pid=0xf99) for new pid=0xfaa > > [mpegts @ 0x7ffe18801200] re-using existing audio stream 2 > (pid=0xf9a) for new pid=0xfab > > This sounds like an interresting feature > this should also get a fate test > It is not the "real" solution, as we still need a flag for PMT updates in AVProgram, or a callback for updated programs - so that API clients can handle all this properly dynamically. But, I do find this an interesting way of handling some cases of PID switch. And under an AVOption it will not break any expectations by default. > > > > > Signed-off-by: Aman Gupta <a...@tmm1.net> > > --- > > doc/demuxers.texi | 4 ++ > > libavformat/mpegts.c | 105 > +++++++++++++++++++++++++++++++++++++++++++++++++-- > > 2 files changed, 105 insertions(+), 4 deletions(-) > > > > diff --git a/doc/demuxers.texi b/doc/demuxers.texi > > index e7c2abce57..2f7d7e0f3a 100644 > > --- a/doc/demuxers.texi > > +++ b/doc/demuxers.texi > > @@ -552,6 +552,10 @@ Show the detected raw packet size, cannot be set by > the user. > > Scan and combine all PMTs. The value is an integer with value from -1 > > to 1 (-1 means automatic setting, 1 means enabled, 0 means > > disabled). Default value is -1. > > + > > +@item merge_pmt_versions > > +Re-use existing streams when a PMT's version is updated and elementary > > +streams move to different PIDs. Default value is 0. > > @end table > > > > @section mpjpeg > > diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c > > index 27b1c30a44..c42e564a7e 100644 > > --- a/libavformat/mpegts.c > > +++ b/libavformat/mpegts.c > > @@ -84,6 +84,8 @@ typedef struct MpegTSSectionFilter { > > unsigned int end_of_section_reached : 1; > > SectionCallback *section_cb; > > void *opaque; > > + int orig_pcr_pid; /* pmt specific */ > > + int last_pcr_pid; > > } MpegTSSectionFilter; > > > > struct MpegTSFilter { > > @@ -147,6 +149,7 @@ struct MpegTSContext { > > int scan_all_pmts; > > > > int resync_size; > > + int merge_pmt_versions; > > > > /******************************************/ > > /* private mpegts data */ > > @@ -172,6 +175,8 @@ static const AVOption options[] = { > > {.i64 = 0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT > | AV_OPT_FLAG_READONLY }, > > {"scan_all_pmts", "scan and combine all PMTs", > offsetof(MpegTSContext, scan_all_pmts), AV_OPT_TYPE_BOOL, > > {.i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM }, > > + {"merge_pmt_versions", "re-use streams when PMT's version/pids > change", offsetof(MpegTSContext, merge_pmt_versions), AV_OPT_TYPE_BOOL, > > + {.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, > > {"skip_changes", "skip changing / adding streams / programs", > offsetof(MpegTSContext, skip_changes), AV_OPT_TYPE_BOOL, > > {.i64 = 0}, 0, 1, 0 }, > > {"skip_clear", "skip clearing programs", offsetof(MpegTSContext, > skip_clear), AV_OPT_TYPE_BOOL, > > @@ -1073,7 +1078,8 @@ static int mpegts_push_data(MpegTSFilter *filter, > > if (ts->skip_changes) > > goto skip; > > > > - pes->st = avformat_new_stream(ts->stream, NULL); > > + if (!pes->st) > > + pes->st = avformat_new_stream(ts->stream, > NULL); > > if (!pes->st) > > return AVERROR(ENOMEM); > > pes->st->id = pes->pid; > > @@ -1982,6 +1988,68 @@ int ff_parse_mpeg2_descriptor(AVFormatContext > *fc, AVStream *st, int stream_type > > *pp = desc_end; > > return 0; > > } > > +static AVStream *find_matching_stream(MpegTSContext *ts, int pid, > > + int stream_id, > > + int pcr_pid, int orig_pcr_pid) > > +{ > > + AVFormatContext *s = ts->stream; > > + int i, orig_pid = orig_pcr_pid + (pid - pcr_pid); > > + AVStream *found = NULL; > > + > > + for (i = 0; i < s->nb_streams; i++) { > > + AVStream *st = s->streams[i]; > > + if (stream_id != -1) { > > + if (st->stream_identifier == stream_id+1) { > > + found = st; > > + break; > > + } > > + } else if (pcr_pid != orig_pcr_pid && st->id == orig_pid) { > > + found = st; > > + break; > > + } > > + } > > + > > + if (found) { > > + av_log(ts->stream, AV_LOG_DEBUG, "re-using existing %s stream > %d (pid=0x%x) for new pid=0x%x\n", > > + av_get_media_type_string(found->codecpar->codec_type), > i, found->id, pid); > > + } > > + > > + return found; > > +} > > + > > > +static int parse_stream_identifier_desc(uint8_t *p, uint8_t *p_end) > > +{ > > + const uint8_t **pp = &p; > > libavformat/mpegts.c:2022:26: warning: initialization from incompatible > pointer type [enabled by default] > Basically, the pointer parameters should be "const". That shuts the warnings at least on clang. > > > + const uint8_t *desc_list_end; > > + const uint8_t *desc_end; > > + int desc_list_len; > > + int desc_len, desc_tag; > > + > > > + desc_list_len = get16(&p, p_end); > > type mismatch: > libavformat/mpegts.c:2028:5: warning: passing argument 1 of ‘get16’ from > incompatible pointer type [enabled by default] > > > [...] > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > Opposition brings concord. Out of discord comes the fairest harmony. > -- Heraclitus > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel