[FFmpeg-devel] [PATCH] avformat/mpegts: add merge_pmt_versions option
Aman Gupta
ffmpeg at tmm1.net
Tue May 15 22:23:08 EEST 2018
On Tue, May 15, 2018 at 5:12 AM, Michael Niedermayer <michael at niedermayer.cc
> wrote:
> On Mon, May 14, 2018 at 03:54:01PM -0700, Aman Gupta wrote:
> > From: Aman Gupta <aman at 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
>
Sure. Can you add a sample to fate-suite:
curl -o fate-suite/mpegts/pmtchange.ts http://0x0.st/secA.ts
>
>
> >
> > Signed-off-by: Aman Gupta <aman at 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.
> > +
> > + at 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]
>
>
> > + 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]
>
Oops, sloppy copy/paste from ff_parse_mpeg2_descriptor on my part. Will fix
for v2.
Thanks for reviewing,
Aman
>
>
> [...]
> --
> Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> Opposition brings concord. Out of discord comes the fairest harmony.
> -- Heraclitus
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>
More information about the ffmpeg-devel
mailing list