Skip to content

Commit

Permalink
Update changed streams on PMT update
Browse files Browse the repository at this point in the history
On playback, when a new version of the PMT (program map table) is received, start
updating the streams at the first stream that is changed, beginning with stream 0,
instead of resetting all streams.
This fixes playback problems that occur when there is a PMT version update in the
first part of the recording that is scanned before the playback starts.
At the start of the playback there is then a PMT change back to the previous version;
this change causes a reset of all stream data; the video playback is then started
with default size of 640x480 and default framerate of 29.97Hz.

Fixes MythTV/mythtv#351
Fixes https://code.mythtv.org/trac/ticket/13557

Signed-off-by: Peter Bennett <pbennett@mythtv.org>
(cherry picked from commit c31db49)
  • Loading branch information
kmdewaal authored and ulmus-scott committed Nov 17, 2021
1 parent 6602903 commit 77526cc
Showing 1 changed file with 32 additions and 40 deletions.
72 changes: 32 additions & 40 deletions libavformat/mpegts-mythtv.c
Expand Up @@ -80,8 +80,8 @@ static int is_pat_same(MpegTSContext *mpegts_ctx,
int *pmt_pnums, int *pmts_pids, unsigned int pmt_count);

static void mpegts_add_stream(MpegTSContext *ts, int id, pmt_entry_t* item, uint32_t prog_reg_desc, int pcr_pid);
static int is_pmt_same(MpegTSContext *mpegts_ctx, pmt_entry_t* items,
int item_cnt);
static int pmt_equal_streams(MpegTSContext *mpegts_ctx,
pmt_entry_t* items, int item_cnt);

typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos);

Expand Down Expand Up @@ -1868,18 +1868,20 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
/* if the pmt has changed delete old streams,
* create new ones, and notify any listener.
*/
if (!is_pmt_same(ts, items, last_item))
int equal_streams = pmt_equal_streams(ts, items, last_item);
if (equal_streams != last_item || ts->pid_cnt != last_item)
{
AVFormatContext *avctx = ts->stream;
int idx;
/* flush out old AVPackets */
ff_read_frame_flush(avctx);

/* delete old streams */
for (idx = ts->pid_cnt-1; idx>=0; idx--)
for (idx = ts->pid_cnt-1; idx >= equal_streams; idx--)
av_remove_stream(ts->stream, ts->pmt_pids[idx], 1);

/* create new streams */
for (idx = 0; idx < last_item; idx++)
for (idx = equal_streams; idx < last_item; idx++)
mpegts_add_stream(ts, h->id, &items[idx], prog_reg_desc, pcr_pid);

/* cache pmt */
Expand Down Expand Up @@ -1923,31 +1925,26 @@ static int is_pat_same(MpegTSContext *mpegts_ctx,
return 1;
}

static int is_pmt_same(MpegTSContext *mpegts_ctx,
pmt_entry_t* items, int item_cnt)
// Find number of equal streams in old and new pmt starting at 0
// and stopping at the first different stream.
static int pmt_equal_streams(MpegTSContext *mpegts_ctx,
pmt_entry_t* items, int item_cnt)
{
int limit = mpegts_ctx->pid_cnt < item_cnt ? mpegts_ctx->pid_cnt : item_cnt;
int idx;
if (mpegts_ctx->pid_cnt != item_cnt)
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG, "mpegts_ctx->pid_cnt=%d != item_cnt=%d\n",
mpegts_ctx->pid_cnt, item_cnt);
#endif
return 0;
}
for (idx = 0; idx < item_cnt; idx++)

for (idx = 0; idx < limit; idx++)
{
/* check for pid */
int loc = find_in_list(mpegts_ctx->pmt_pids, items[idx].pid);
if (loc < 0)
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG,
"find_in_list(..,[%d].pid=%d) => -1\n"
"is_pmt_same() => false\n",
"find_in_list(..,[%d].pid=%d) => -1\n",
idx, items[idx].pid);
#endif
return 0;
break;
}

/* check stream type */
Expand All @@ -1956,31 +1953,28 @@ static int is_pmt_same(MpegTSContext *mpegts_ctx,
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG,
"mpegts_ctx->pids[items[%d].pid=%d] => null\n"
"is_pmt_same() => false\n",
"mpegts_ctx->pids[items[%d].pid=%d] => null\n",
idx, items[idx].pid);
#endif
return 0;
break;
}
if (tss->type == MPEGTS_PES)
{
PESContext *pes = (PESContext*) tss->u.pes_filter.opaque;
if (!pes)
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG, "pes == null, where idx %d\n"
"is_pmt_same() => false\n", idx);
av_log(NULL, AV_LOG_DEBUG, "pes == null, where idx %d\n", idx);
#endif
return 0;
break;
}
if (pes->stream_type != items[idx].type)
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG,
"pes->stream_type != items[%d].type\n"
"is_pmt_same() => false\n", idx);
"pes->stream_type != items[%d].type\n", idx);
#endif
return 0;
break;
}
}
else if (tss->type == MPEGTS_SECTION)
Expand All @@ -1989,35 +1983,33 @@ static int is_pmt_same(MpegTSContext *mpegts_ctx,
if (!sect)
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG, "sect == null, where idx %d\n"
"is_pmt_same() => false\n", idx);
av_log(NULL, AV_LOG_DEBUG, "sect == null, where idx %d\n", idx);
#endif
return 0;
break;
}
if (sect->stream_type != items[idx].type)
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG,
"sect->stream_type != items[%d].type\n"
"is_pmt_same() => false\n", idx);
"sect->stream_type != items[%d].type\n", idx);
#endif
return 0;
}
break;
}
}
else
{
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG,
"tss->type != MPEGTS_PES, where idx %d\n"
"is_pmt_same() => false\n", idx);
"tss->type != MPEGTS_PES, where idx %d\n", idx);
#endif
return 0;
break;
}
}
#ifdef DEBUG
av_log(NULL, AV_LOG_DEBUG, "is_pmt_same() => true\n", idx);
av_log(NULL, AV_LOG_DEBUG, "pmt_equal_streams:%d old:%d new:%d limit:%d\n",
idx, mpegts_ctx->pid_cnt, item_cnt, limit);
#endif
return 1;
return idx;
}

static void mpegts_cleanup_streams(MpegTSContext *ts)
Expand Down

0 comments on commit 77526cc

Please sign in to comment.